如何使用find重命名多个文件

如何使用find重命名多个文件

我想使用find命令重命名多个文件(file1 ... fileN 到 file1_renamed ... fileN_renamed):

find . -type f -name 'file*' -exec mv filename='{}' $(basename $filename)_renamed ';'

但出现此错误:

mv: cannot stat ‘filename=./file1’: No such file or directory

这不起作用,因为文件名不被解释为 shell 变量。

答案1

以下是您的方法的直接修复:

find . -type f -name 'file*' -exec sh -c 'x="{}"; mv "$x" "${x}_renamed"' \;

但是,如果您有大量匹配文件,则这是非常昂贵的,因为您mv为每个匹配启动一个新的 shell(执行 a )。如果任何文件名中包含有趣的字符,就会爆炸。更有效、更安全的方法是:

find . -type f -name 'file*' -print0 | xargs --null -I{} mv {} {}_renamed

它还具有处理名称奇怪的文件的好处。如果find支持的话,这可以减少到

find . -type f -name 'file*' -exec mv {} {}_renamed \;

xargs版本在不使用时很有用{},如

find .... -print0 | xargs --null rm

这里rm被调用一次(或者对于很多文件多次),但不是每个文件。

我删除了basename您的问题,因为它可能是错误的:您会移至foo/bar/file8file8_renamed而不是foo/bar/file8_renamed

编辑(如评论中建议的):

  • 添加缩短findxargs
  • 添加了安全贴纸

答案2

尝试后第一个答案稍微玩弄一下,我发现它可以使用以下命令来稍微缩短和简化-execdir

find . -type f -name 'file*' -execdir mv {} {}_renamed ';'

看起来它也应该完全满足您的需要。

答案3

另一种方法是使用while read循环输出find。这允许将每个文件名作为可以操纵的变量进行访问,而不必担心sh -c使用find's-exec选项生成单独进程的额外成本/潜在安全问题。

find . -type f -name 'file*' |
    while IFS= read file_name; do
        mv "$file_name" "${file_name##*\/}_renamed"
    done

如果正在使用的 shell 支持-d指定read分隔符的选项,您可以使用以下命令支持奇怪命名的文件(例如,使用换行符):

find . -type f -name 'file*' -print0 |
    while IFS= read -d '' file_name; do
        mv "$file_name" "${file_name##*\/}_renamed"
    done

答案4

我能够用 、 和 做类似forfind事情mv

for i in $(find . -name 'config.yml'); do mv $i $i.bak; done

这会找到所有config.yml文件并将它们重命名为config.yml.bak

相关内容