
比方說,我有一個包含一堆檔案(例如 g.txt)的目錄,其中 g.txt 的最後修改時間是 2012 年 6 月 20 日。
如何批次重命名所有文件(如 g.txt)並在末尾附加最後修改日期 2012 年 6 月 20 日?
答案1
這是 goldschrafe 的一句台詞的一個版本:
不使用統計數據
適用於早期版本的 GNU 日期
正確處理檔案名稱中的任何空格
也可以處理以破折號開頭的檔名
for f in *; do mv -- "$f" "$f-$(date -r "$f" +%Y%m%d)"; done
更新2021-03-20
我對這個問題的回答多年來一直困擾著我(好吧,只有當我記得它時 - 像今天這樣的日子,當它再次獲得贊成票時)所以我終於更新它了。我上面的原始答案仍然有效,但下面更新的答案更好。
喜歡任何批次檔重命名操作,這應該使用珀爾 rename
實用程序,而不是使用一些笨重的 shell for 循環。
perl 重新命名實用程式實際上是一種專門的腳本語言,它允許您使用任何 perl 程式碼來重命名文件,從簡單的s/search/replace/
正規表示式操作(足以滿足大多數重命名任務)到複雜的多行腳本。
例如
rename -n 'BEGIN {use Date::Format};
die $! unless -f $_;
next if (m/-\d{8}$/);
my $ts=(stat($_))[9];
my $dt=time2str("%Y%m%d",$ts);
s/$/-$dt/;' *.txt
這只需要 perl 和Date::Format
模組(這個模組非常有用,應該安裝在任何帶有 perl 的系統上。IMO 它,以及作者 Graham Barr 的Date::Parse
模組,應該是 Perl 核心模組庫的一部分,但它不是,所以你必須使用cpan
發行版套件(如 Debianlibtimedate-perl
套件)來安裝它。
順便說一句,此腳本會跳過任何看起來檔案名稱末尾已包含日期(即 8 位數字)的檔案。
或者,對於將日期放在文件後綴(如果有)之前的更高級版本:
rename -n 'BEGIN {use Date::Format; use File::Basename};
die $! unless -f $_;
my ($filename,$dirs,$suffix) = fileparse($_,qr/\.[^.]*/);
next if (m/-\d{8}${suffix}$/);
my $ts=(stat($_))[9];
my $dt=time2str("%Y%m%d",$ts);
s/${suffix}$/-${dt}${suffix}/;' *.txt
這個版本沒有額外的要求,因為File::Basename
從我記事起(至少十年,可能更久),該模組就被作為 perl 的標準核心模組包含在內。
筆記:上面的兩個rename
腳本都使用 rename 的-n
(又名--nono
)“dry-run”選項,以便可以在應用之前測試/模擬結果。當您確定它可以滿足您的要求時,請刪除-n
(或將其替換為詳細輸出)。-v
另請注意:與任何其他 Perlrename
腳本一樣,這可以重命名命令列和/或標準輸入提供的檔案名稱。例如,重新命名目前目錄和所有子目錄中的所有 .txt 檔案:
find . -type f -iname '*.txt' -print0 |
rename -0 --nofullpath -n '..........'
順便說一句,我在這裡使用了rename
--nofullpath (又名-d
, --filenmame
, --nopath
)選項來確保它僅重命名找到的任何檔案路徑的檔案名稱部分。在這種特殊情況下不需要它(因為範例重命名腳本僅更改檔案名稱的末尾),但當您不想重命名路徑和檔案名稱時通常是一個好主意(例如重命名腳本,例如's/ //g'
剝離space from filenames會嘗試刪除路徑中的所有空格以及不含的檔案名--nofullpath
,可能會導致它失敗並出現錯誤)。
最後:不要將 perl 重新命名腳本(又名File::Rename
,或有時prename
在 Fedora 和 RedHat 上調用,或perl-rename
)與任何其他名為 rename 的程式混淆。 僅有的這個基於 Perl 的重命名實用程式可以使用任意 Perl 程式碼重命名文件,如上所示,任何其他重命名實用程式將具有不同的功能和不同且不相容的命令列選項。
您可以檢查是否安裝了正確的重新命名:
$ rename -V
/usr/bin/rename using File::Rename version 1.13, File::Rename::Options version 1.10
可執行檔可能在您的系統上被呼叫prename
或perl-rename
或,因此請嘗試使用這些文件,並調整上面的範例以使用正確的可執行檔名稱。file-rename
-V
答案2
快速而骯髒的 Bash 一行程式碼將目前目錄中的所有(通配符)檔案從 重新命名filename.txt
為filename.txt-20120620
:
for f in *; do mv -- "$f" "$f-$(stat -c %Y "$f" | date +%Y%m%d)"; done
我確信,一個有進取心的 Bash 書呆子會找到一些邊緣情況來打破它。 :)
顯然,這並不能實現理想的效果,例如檢查文件末尾是否已經有看起來像日期的內容。
答案3
強制性的 zsh 單行(不包括可選組件的一次性載入):
zmodload zsh/stat
autoload -U zmv
zmv -n '(*)' '$1-$(stat -F %Y%m%d +mtime -- $1)'
我們使用stat
內建的zsh/stat
模組,以及zmv
重命名檔案的功能。這是一個額外的內容,將日期放在延期之前(如果有的話)。
zmv -n '(*)' '$1:r-$(stat -F %Y%m%d +mtime -- $1)${${1:e}:+.$1:e}'
答案4
這是 cas 的 oneliner 的版本,(基於 goldschrafe 的 oneliner)擴展為冪等性,
即擴展到帶有日期時間前綴的檔案和僅對那些還沒有日期時間前綴的人執行此操作。
使用案例:如果您將新檔案新增至目錄並希望為尚未新增日期時間前綴的檔案新增日期時間前綴,則很有幫助。
for f in * ; do
if [[ "$f" != ????-??-??' '??:??:??' - '* ]]; then
mv -v -- "$f" "$(date -r "$f" +%Y-%m-%d' '%H:%M:%S) - $f" ;
fi;
done