有没有办法仅使用 find 命令在文件名前面添加一个字符串?
这样:
201a.txt
201b.png
...
就变成这样了:
foo_201a.txt
foo_201b.png
...
这:
find . -name '201*' -execdir mv {} foo_{} \;
不起作用,因为该{}
部分包含文件名中的前导./
,因此尝试写入foo_./201*
.
如果仅使用 find 无法做到这一点,那么将字符串添加到文件名的最可移植(阅读:仅 coreutils,没有 shell 脚本,最容易理解)的方法是什么?
答案1
不。但是该rename
命令提供了一个简单的解决方案。
$ ls -1
201a.txt
201b.png
$ rename 201 foo_201 201*
$ ls -1
foo_201a.txt
foo_201b.png
$
答案2
怎么样
find . -name '201*' -execdir basename {} \; | xargs -I{} mv {} foo_{}
basename
是由提供的coreutils
,并且由于xargs
是由提供的,因此findutils
它应该至少与find -execdir
它本身一样可移植。
或者,仅使用 POSIX shell 功能
find . -name '201*' -execdir sh -c 'mv "$1" "foo_${1#*/}"' sh {} \;
答案3
单独使用这是不可能的find
,即使使用 GNU find 也是不可能的。 GNU find 可以打印删除命令行前缀并添加另一个前缀的文件,方法是使用-printf foo_%p
代替-print
,但是 没有任何类似的东西-exec
。
(find -printf 'mv foo_%p …' | sh
如果你喜欢危险地生活,你可以使用 , 。这只适用于“驯服”的文件名,如果文件名中有空格、引号和其他特殊字符,它会严重中断。所以不要这样做。)
执行此操作的标准方法(就像在任何 POSIX 系统上工作的方式一样,也是一种常见的方式)是调用 shell 来执行字符串操作。
find . -name '201*' -exec sh -c 'mv -- "$0" "${0%/*}/foo_${0##*/}"' {} \;
我不使用它,-execdir
因为它是一个 GNU 扩展,而你要求可移植性。请注意,它{}
作为参数传递给 shell。切勿在 shell 代码内部使用{}
:不仅因为它不可移植,而且最重要的是因为它会导致文件名被解释为 shell 代码,如果文件名包含特殊字符,则会失败。
在现代 POSIX 系统(过去十年的任何系统)上,您可以通过批处理 shell 调用来稍微加快此命令的速度。
find . -name '201*' -exec sh -c 'for x do mv -- "$x" "${x%/*}/foo_${x##*/}"; done' sh {} +
或者,在 ksh、bash 或 zsh 中,您可以使用递归通配符而不是调用find
.
set -o globstar # ksh only
shopt -s globstar # bash only
for x in **/201*; do
mv -- "$x" "${x%/*}/foo_${x##*/}"
done
答案4
您可以使用星号 ( *
) 来代替,它会删除该./
部分:
find * -name '201*' -exec mv {} foo_{} \;