Đổi tên một loạt các tệp có dấu thời gian sửa đổi ngày ở cuối tên tệp?


14

Vì vậy, giả sử, tôi có một thư mục chứa một loạt các tệp như g.txt, trong đó g.txt được sửa đổi lần cuối vào ngày 20 tháng 6 năm 2012.

Làm cách nào để tôi đổi tên hàng loạt tất cả các tệp (như g.txt) với ngày sửa đổi cuối cùng vào ngày 20 tháng 6 năm 2012 được thêm vào cuối?

Câu trả lời:


13

Bash one-liner nhanh và bẩn để đổi tên tất cả các tệp (toàn cầu) trong thư mục hiện tại từ filename.txtsang filename.txt-20120620:

for f in *; do mv -- "$f" "$f-$(stat -c %Y "$f" | date +%Y%m%d)"; done

Một mọt sách Bash táo bạo sẽ tìm thấy một số trường hợp cạnh để phá vỡ nó, tôi chắc chắn. :)

Rõ ràng, điều này không làm những điều mong muốn như kiểm tra xem một tập tin đã có một cái gì đó trông giống như một ngày ở cuối.


2
+1, có vẻ tốt. bạn có thể làm cho nó mạnh mẽ hơn một chút bằng cách sử dụng '-' làm đối số đầu tiên cho mv. Những người bảo vệ chống lại những kẻ thù bắt đầu bằng '-'
cas

5
Đó là loại datethực hiện gì? GNU của tôi datedường như không xử lý đầu vào.
manatwork

coreutils 8.4 trên RHEL 6.
jgoldschrafe

2
@jgoldschrafe, bạn có chắc rằng mã đó phù hợp với bạn không? pastebin.com/nNYubf3A
manatwork

5
bắt tốt manatwork. GNU ngày 8.13 của tôi cũng không hỗ trợ đọc từ stdin. Nó hỗ trợ sử dụng thời gian mod của tệp với "-r" - ví dụ: "ngày +% Y% m% d -r $ f", do đó, thậm chí không cần thiết trong trường hợp cụ thể này.
cas

18

đây là phiên bản của one-liner của goldschrafe:

  • không sử dụng stat
  • hoạt động với các phiên bản trước của ngày GNU
  • đối phó chính xác với bất kỳ khoảng trắng nào trong tên tệp
  • cũng đối phó với tên tệp bắt đầu bằng dấu gạch ngang

    for f in *; do mv -- "$f" "$f-$(date -r "$f" +%Y%m%d)"; done


1
Bạn nên làm cho nó date -r "$f" +%Y%m%dhoặc nó sẽ không hoạt động nếu POSIXLY_CORRECTtrong môi trường. Nói chung, các tùy chọn nên đi trước các đối số khác.
Stéphane Chazelas

đây sẽ là "câu trả lời đúng"
invalidusername

Tất nhiên bạn không cần niềng răng trong "${f}".
G-Man nói 'Phục hồi Monica'

nhưng làm thế nào bạn có thể làm cho nó sao cho ngày chúng tôi đặt trước, ví dụ "Tên tệp Ymd"?
timebandit

2

Bắt buộc zsh one-liner (không tính tải một lần các thành phần tùy chọn):

zmodload zsh/stat
autoload -U zmv
zmv -n '(*)' '$1-$(stat -F %Y%m%d +mtime -- $1)'

Chúng tôi sử dụng statnội dung dựng sẵn từ zsh/statmô-đunzmvchức năng để đổi tên tệp. Và đây là một phần bổ sung đặt ngày trước khi gia hạn, nếu có.

zmv -n '(*)' '$1:r-$(stat -F %Y%m%d +mtime -- $1)${${1:e}:+.$1:e}'

1

Theo tôi hiểu, chúng tôi không biết trước ngày sửa đổi là gì. Vì vậy, chúng ta cần lấy nó từ mỗi tệp, định dạng đầu ra và đổi tên từng tệp theo cách để nó bao gồm ngày sửa đổi trong tên tệp.

Bạn có thể lưu tập lệnh này dưới dạng "modif_date.sh" và làm cho tập lệnh thực thi. Chúng tôi gọi nó với thư mục đích làm đối số:

modif_date.sh txt_collection

Trong đó "txt_collection" là tên của thư mục nơi chúng tôi có tất cả các tệp mà chúng tôi muốn đổi tên.

#!/bin/sh

# Override any locale setting to get known month names
export LC_ALL=c
# First we check for the argument
if [ -z "$1" ]; then
    echo "Usage: $0 directory"
    exit 1
fi

# Here we check if the argument is an absolute or relative path. It works both ways
case "${1}" in
  /*) work_dir=${1};;
  *) work_dir=${PWD}/${1};;
esac

# We need a for loop to treat file by file inside our target directory
for i in *; do
    # If the modification date is in the same year, "ls -l" shows us the timestamp.
    # So in this case we use our current year. 
    test_year=`ls -Ggl "${work_dir}/${i}" | awk '{ print $6 }'`
    case ${test_year} in *:*) 
        modif_year=`date '+%Y'`
        ;;
    *)
        modif_year=${test_year}
        ;;
    esac
    # The month output from "ls -l" is in short names. We convert it to numbers.
    name_month=`ls -Ggl "${work_dir}/${i}" | awk '{ print $4 }'`
    case ${name_month} in
            Jan) num_month=01 ;;
            Feb) num_month=02 ;;
        Mar) num_month=03 ;;
        Apr) num_month=04 ;;
        May) num_month=05 ;;
        Jun) num_month=06 ;;
        Jul) num_month=07 ;;
        Aug) num_month=08 ;;
        Sep) num_month=09 ;;
        Oct) num_month=10 ;;
        Nov) num_month=11 ;;
        Dec) num_month=12 ;;
        *) echo "ERROR!"; exit 1 ;;
    esac
    # Here is the date we will use for each file
    modif_date=`ls -Ggl "${work_dir}/${i}" | awk '{ print $5 }'`${num_month}${modif_year}
    # And finally, here we actually rename each file to include
    # the last modification date as part of the filename.
    mv "${work_dir}/${i}" "${work_dir}/${i}-${modif_date}"
done

1
đọc trang man cho stat (1) để tìm hiểu làm thế nào bạn có thể thu nhỏ tập lệnh của mình khoảng 3/4 ... hầu hết những điều trên là phát minh lại bánh xe. đặc biệt, 'stat -c% Y' sẽ cung cấp cho bạn thời gian sửa đổi của tệp trong vài giây kể từ kỷ nguyên (1970-01-01 00:00:00). Điều này sau đó có thể được sử dụng làm đầu vào cho đến ngày (1) để định dạng dấu thời gian theo yêu cầu. xem câu trả lời của jgoldschrafe ở trên để biết ví dụ.
cas

@CraigSanders Ưu điểm là tập lệnh này hoạt động trong các hệ điều hành khác ngoài Linux, có một stattiện ích khác hoặc không có gì cả.
Gilles 'SO- đừng trở nên xấu xa'

Lưu ý rằng phân tích cú pháp đầu ra lslà không đáng tin cậy . Trên một số biến thể unix, tên người dùng và nhóm có thể chứa khoảng trắng, sẽ loại bỏ sự liên kết của các cột ngày.
Gilles 'SO- ngừng trở nên xấu xa'

@giles: đúng, nhưng bất kỳ ai hợp lý :-) sẽ cài đặt GNU coreutils (và tất cả các công cụ GNU khác) trên bất kỳ hệ thống không phải linux nào. Đó là cách dễ nhất để có được không chỉ một bộ công cụ người dùng tốt mà còn là một bộ nhất quán bất kể hạt nhân bên dưới.
cas

1
(Tiếp theo) ... (5) lỗi khác: nó giả định rằng bất kỳ ngày / thời gian hiển thị bởi ls một ngày và trong một thời gian (chứ không phải một ngày và một năm) phải trong năm nay. Đây không phải là sự thật. Đó là trong sáu tháng qua; đó có thể là trong năm trước (ví dụ: 27 tháng 9 năm 2016 đến 31 tháng 12 năm 2016 trong vòng sáu tháng qua). (6) Có nguy cơ làm vẹt Wiki của Greg (mà @Gilles đã trích dẫn), tên tệp có chứa dòng mới và dấu cách có thể khiến điều này thất bại. Tiết (Cont'd)
G-Man nói 'Tái lập lại' '

0

Đây là phiên bản của cas-liner, (dựa trên oneliner của goldschrafe) được mở rộng với sự bình tĩnh ,

tức là mở rộng cho các tệp tiền tố với thời gian ngày và chỉ làm điều này cho những người chưa có tiền tố thời gian ngày .

Ca sử dụng: hữu ích nếu bạn thêm tệp mới vào thư mục và muốn thêm tiền tố thời gian ngày cho những người chưa có.

for f in * ; do
  if [[ "$f" != ????-??-??' '??:??:??' - '* ]]; then
    mv -v -- "$f" "$(date -r "$f" +%Y-%m-%d' '%H:%M:%S) - $f" ;
  fi;
done

Nếu dấu thời gian tệp của bạn bị vặn và là jpeg, bạn có thể muốn sửa lỗi với dữ liệu EXIF: for f in *.jpg ; do jhead -ft "$f" ; donenguồn: unix.stackexchange.com/a/290755/9689
Grzegorz Wierzowiecki
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.