比如说,我有一个包含一堆文件(例如 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