我最近下载了一些文件,我想给它们命名。可以这样做:
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 字符分隔的文件,然后sort
、head
和xargs
都将接受它作为分隔符而不是换行符 - 使整个过程更加一致。如果您知道如何执行此操作,并希望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)