使用find和sed递归重命名文件

我想通过一堆目录,并重命名以_test.rb结尾的所有文件,而不是以_spec.rb结尾。 这是我从来没有想过如何处理bash的事情,所以这次我想我会努力让它钉上。 尽管我到目前为止只是想尽一点办法,但我的最大努力是:

find spec -name "*_test.rb" -exec echo mv {} `echo {} | sed s/test/spec/` ;

注意:在exec之后有一个额外的回显,以便在测试它时打印命令而不是运行。

当我运行它时,每个匹配的文件名的输出是:

mv original original

即sed的替代已经丢失。 有什么诀窍?


发生这种情况是因为sed收到字符串{}作为输入,可以通过以下方式进行验证:

find . -exec echo `echo "{}" | sed 's/./foo/g'` ;

它以递归方式为目录中的每个文件打印foofoo 。 这种行为的原因是管道在扩展整个命令时由shell执行一次。

没有办法以这种方式引用sed管道, find会为每个文件执行它,因为find不会通过shell执行命令,也没有管道或反引号的概念。 GNU findutils手册解释了如何通过将管道放入单独的shell脚本来执行类似的任务:

#!/bin/sh
echo "$1" | sed 's/_test.rb$/_spec.rb/'

(可能有一些不正当的方法使用sh -c和一大堆引用来完成所有这些命令,但我不会去尝试。)


以最接近原始问题的方式解决它可能会使用xargs“每命令行参数”选项:

find . -name *_test.rb | sed -e "p;s/test/spec/" | xargs -n2 mv

它会递归地查找当前工作目录中的文件,回显原始文件名( p ),然后修改名称( s/test/spec/ ),并将它们全部成对( xargs -n2 )输入到mv 。 请注意,在这种情况下,路径本身不应包含字符串test


你可能想要考虑其他方式

for file in $(find . -name "*_test.rb")
do 
  echo mv $file `echo $file | sed s/_test.rb$/_spec.rb/`
done
链接地址: http://www.djcxy.com/p/78329.html

上一篇: Recursively rename files using find and sed

下一篇: How to copy a file to multiple directories using the gnu cp command