注意事项

注意事项

我最近下载了一些文件,我想给它们命名。可以这样做:

rename 's/ /_/g' $(ls -t | head -n5) 

实际上,我想重命名最后下载的 5 个文件。

任何想法?

答案1

首先,我必须指出,解析ls通常不被推荐。它的输出是供人类使用的,并且此解决方案对于某些合法的文件名(例如包含换行符的文件名)会失败

话虽如此,最简单的解决方案似乎是使用ls(因为find不提供按修改日期排序选项)。为此,您可以使用管道和命令xargs来执行最终重命名。

简而言之:

ls -1t | head -n5 | xargs -I {} rename 's/ /_/g' {}

这几乎完全使用了您的原始命令,但xargs完成了最后的完成。xargs将接受多个换行符分隔的参数,并将它们全部传递给单个rename命令。

注意事项

这应该可行 - 但解析ls很脆弱。对于包含换行符的文件名,这会中断;使用专门用于解析的命令find会更好。

但是,我不知道如何使用按上次修改日期排序find。如果其他人知道如何做到这一点,你可能会得到类似这样的结果:

find . -mindepth 1 -maxdepth 1 -print0 | sort <???> -Z | head -z -n5 | xargs -0 rename 's/ /_/g'

如果<???>是有效参数,则此命令链将指示find在当前目录中输出用 NUL 字符分隔的文件,然后sortheadxargs都将接受它作为分隔符而不是换行符 - 使整个过程更加一致。如果您知道如何执行此操作,并希望ls用此底部部分替换答案,请随意评论或编辑此内容。

答案2

正如已经指出的那样,解析ls很脆弱。如果您的文件名有任何类型的奇怪内容(空格、换行符、控制字符等),它就会中断。由于您想用 替换空格_,因此您建议的方法将失败。一种安全的方法是:

stat --printf '%n/%Y\0' * | sort -rz -t'/' -k 2 | head -z -n 3 | 
    cut -d'/' -z -f 1 | xargs -0 perl-rename 's/ /_/g'
  • stat --printf '%n/%Y\0' *:这将打印出当前目录中每个文件或目录的名称(%n),后跟斜杠(/;我使用斜杠,因为文件名中不允许使用斜杠,因此可以安全地将其用作分隔符)和文件自纪元以来的修改时间( ),以秒为单位%Y,最后是空字符(\0)。
  • sort -rz -k 2:这将采用 NULL 分隔的输入 ( ) 并根据每行 ( ) 的第二个分隔 ( ) 字段中的值按-z相反的顺序对其进行排序 ( ) 。-r/-t'/'-k 2
  • head -z -n 5:保留前 5(-n 5)个以空字符分隔的(-z)行。
  • cut -d'/' -z -f 1:打印第一个 ( -f 1)/分隔的 ( -d /) 字段的空分隔 ( -z) 数据。

答案3

我刚刚ls -q尝试了一下:

IFS='
'
for file in `ls -tr1q|tail -n5`; do
  rename 's/ /_/g' "$file"
done

是否进行所需的重命名,即使对于带有换行符或其他控制字符的文件名,也会出现错误:

Unsuccessful stat on filename containing newline at /usr/bin/rename line 59

(使用 perl v5.20.2)

相关内容