我正在使用“查找”来重命名文件。
这有效:find . -iname a* -exec bash -c 'x={};mv {} ${x/a/b}' \;
但这并没有:
find . -iname a* -exec bash -c "x={};mv {} ${x/a/b}" \;
为什么?
在 Bash 上运行。
谢谢
答案1
首先,请参阅:shell 中的 "..."、'...'、$'...' 和 $"..." 引号之间有什么区别?
这有效:
find . -iname a* -exec bash -c 'x={};mv {} ${x/a/b}' \;
如果当前目录中没有任何以 开头的文件名a
,并且树中的任何文件名没有空格或 shell 特有的字符,那么是的,也许它会起作用。
但这并没有:
find . -iname a* -exec bash -c "x={};mv {} ${x/a/b}" \;
该"x={};mv {} ${x/a/b}"
部分是用双引号引起来的,因此 shell${...}
在运行命令之前会在此处展开。find
可能只会看到结果字符串x={};mv {}
,因为$x
不太可能在外壳中设置。
在第一个中,单引号防止扩展,因此find
see x={};mv {} ${x/a/b}
,替换文件名{}
并将结果传递到您要求其运行的 shell。它可能会起作用。
然而,这存在一些问题。第一个是未引用的-iname a*
。这将在运行之前在 shell 中展开 glob find
,因此如果您的目录包含 egabcd.txt
和asdf.txt
,它将与运行相同find . -iname abcd.txt asdf.txt
。第一个文件名带有-iname
,第二个文件名是错误。
然后,替换{}
.考虑foo bar.txt
在树中某处找到的文件名,例如。find
更改x={};mv {} ${x/a/b}
为x=foo bar.txt;mv foo bar.txt ${x/a/b}
并在 shell 中运行它。但这不是您想要的语法,它将分配foo
给x
, 并运行bar.txt
, 并作为命令。像这样混合代码和数据几乎不可能起作用,特别是对于可以包含以下内容的文件名任何字符。这也打开了一个明显的命令注入漏洞,例如文件名类似于foo; echo doing bad things
.
正确的方法是将文件名作为位置参数传递给内壳,并引用脚本中的扩展。
所以,
find . -iname "a*" -exec bash -c 'mv "$1" "${1/a/b}"' sh {} \;
看: