Bash:递归重命名文件的一部分
Bash:递归重命名文件的一部分
我想遍历一系列目录,将所有以_test.rb结尾的文件重命名为以_spec.rb结尾的文件。这是我从未完全掌握如何使用bash完成的事情,所以这次我打算花些功夫来解决它。然而,目前我还没有找到解决方法,我最好的尝试是:\n
find spec -name "*_test.rb" -exec echo mv {} `echo {} | sed s/test/spec/` \;
\n注意:在exec之后有一个额外的echo,这样在我测试时会打印出命令而不是运行它。\n当我运行它时,每个匹配的文件名的输出是:\n
mv original original
\n即sed的替换已经丢失了。有什么诀窍吗?
问题的原因:需要批量递归地将文件名中的"_test.rb"替换为"_spec.rb"。
解决方法:使用Bash命令递归地重命名文件名中的一部分。
具体的解决方法如下:
for file in $(find . -name "*_test.rb") do echo mv $file `echo $file | sed s/_test.rb$/_spec.rb/` done
这是一个简单的循环命令,通过查找所有文件名为"\*_test.rb"的文件,并将其重命名为"\*_spec.rb"。
另外,还可以将上述命令改写为单行命令,如下:
for file in $(find . -name "*_test.rb"); do echo mv $file `echo $file | sed s/_test.rb$/_spec.rb/`; done
需要注意的是,如果文件名中包含空格,则上述命令将无法正常工作。可以通过设置for循环仅在换行符上分割文件名来解决这个问题。可以参考cyberciti.biz/tips/handling-filenames-with-spaces-in-bash.html中的示例来实现。
另外,也可以使用find命令的-exec选项来进行重命名操作,如下:
find . -name "*_test.rb" -exec bash -c 'mv "$0" "${0/_test.rb/_spec.rb}"' {} \;
以上就是解决在Bash中递归地重命名文件名的问题的方法。
在Bash中递归重命名文件的一部分,出现问题的原因是sed
接收到输入的字符串{}
,可以通过以下命令进行验证:
find . -exec echo `echo "{}" | sed 's/./foo/g'` \;
该命令会递归地为目录中的每个文件打印foofoo
。这种行为的原因是整个命令在shell扩展时由shell执行一次。
没有办法以一种引用sed
管道的方式来执行find
,使其对每个文件执行一次命令,因为find
不通过shell执行命令,也没有管道或反引号的概念。GNU findutils手册解释了如何通过将管道放在单独的shell脚本中来执行类似的任务:
#!/bin/sh echo "$1" | sed 's/_test.rb$/_spec.rb/'
(也许有一些古怪的使用sh -c
和大量引号的方式可以在一个命令中完成所有这些,但我不会尝试。)
对于那些好奇在这里使用sh -c的古怪用法,以下是示例代码:find spec -name "*_test.rb" -exec sh -c 'echo mv "$1" "$(echo "$1" | sed s/test.rb\$/spec.rb/)"' _ {} \;
这个下划线是什么?很棒的解决方案-但我更喜欢ramtam的答案:)
谢谢!节省了我很多麻烦。为了完整起见,这是我将其管道化到脚本的方法:find . -name "file" -exec sh /path/to/script.sh {} \;
Bash: 递归重命名文件中的一部分
在处理文件名时,有时候需要递归地重命名文件中的一部分。下面是一个解决方案,可以通过使用xargs的"args per command line"选项来实现。
find . -name "*_test.rb" | sed -e "p;s/test/spec/" | xargs -n2 mv
这段代码会递归地在当前工作目录中查找文件,然后将原始文件名(p
)和修改后的文件名(s/test/spec/
)输出,并以一对一对的方式传递给mv
命令(xargs -n2
)。需要注意的是,路径本身不应该包含字符串test
。
不幸的是,这种方法存在空格的问题。如果文件夹名中包含空格,会导致xargs命令出错(可以通过使用-p选项来确认是否出错,进入交互模式)。
这正是我所需要的。可惜存在空格的问题(虽然我没有进行测试)。但对于我目前的需求来说,它是完美的。我建议先使用"echo"而不是"mv"作为"xargs"参数进行测试。
如果你需要处理路径中的空格,并且你使用的是GNU sed >= 4.2.2,那么你可以使用-z
选项,结合find的-print0
和xargs的-0
选项:
find -name '*._test.rb' -print0 | sed -ze "p;s/test/spec/" | xargs -0 -n2 mv
这是最佳解决方案。比使用find -exec要快得多。谢谢你。
如果路径中有多个test
文件夹,则这种方法不起作用。sed
只会重命名第一个文件夹,mv
命令会因为找不到文件或目录而报错。