查找命令:单引号与双引号

查找命令:单引号与双引号

我正在使用“查找”来重命名文件。

这有效: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不太可能在外壳中设置。

在第一个中,单引号防止扩展,因此findsee x={};mv {} ${x/a/b},替换文件名{}并将结果传递到您要求其运行的 shell。它可能会起作用。


然而,这存在一些问题。第一个是未引用的-iname a*。这将在运行之前在 shell 中展开 glob find,因此如果您的目录包含 egabcd.txtasdf.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 中运行它。但这不是您想要的语法,它将分配foox, 并运行bar.txt, 并作为命令。像这样混合代码和数据几乎不可能起作用,特别是对于可以包含以下内容的文件名任何字符。这也打开了一个明显的命令注入漏洞,例如文件名类似于foo; echo doing bad things.


正确的方法是将文件名作为位置参数传递给内壳,并引用脚本中的扩展。

所以,

find . -iname "a*" -exec bash -c 'mv "$1" "${1/a/b}"' sh {} \;

看:

相关内容