在" find -exec"中使用eval时出现意外行为

时间:2017-07-23 10:18:15

标签: linux bash shell unix find

当我遇到这个奇怪的问题时,我试图批量重命名并使用bash在文件夹中移动一些文件。

我试图将每个PNG文件移动到文件层次结构中的一个目录中。首先我跑了:

find . -name *png -exec echo {} \;

一切都按预期工作:

./res/drawable-xxxhdpi/ic_pickonmap.png
./res/drawable-hdpi/ic_pickonmap.png
./res/drawable-mdpi/ic_pickonmap.png
./res/drawable-xxhdpi/ic_pickonmap.png
./res/drawable-xhdpi/ic_pickonmap.png

然后我运行了以下内容:

find . -name *png -exec dirname {} \;

按预期打印:

./res/drawable-xxxhdpi
./res/drawable-hdpi
./res/drawable-mdpi
./res/drawable-xxhdpi
./res/drawable-xhdpi

但是当我简单地回应dirname的评价时,它表现得非常奇怪。当我执行时:

find . -name *png -exec echo `dirname {}` \;

它只打印点

[blackvvine@unweeded-garden icon.bac]$ find . -name *png -exec echo `dirname {}` \;
.
.
.
.
.

解决移动文件的问题不是我的意图。我最终用以下方法解决了这个问题:

find . -name *.png -exec bash -c 'mv $1 `dirname $1`/..' _ {} \;

我的问题是为什么会发生这种情况。我一直认为回应命令的评估与运行命令完全相同。

1 个答案:

答案 0 :(得分:4)

执行此find命令时:

find . -name '*.png' -exec echo `dirname {}` \;

它有效地执行此命令:

find . -name '*.png' -exec echo . \;

这是因为命令替换,即由反引号“...”包围的部分,在执行find命令之前发生,并且{}被单个点替换。

您可以通过运行bash -cx(启用调试)来验证这一点:

bash -cx 'find . -name "*.png" -exec echo $(dirname {}) \;'
++ dirname '{}'
+ find . -name '*.png' -exec echo . ';'
.
.

您可以先看dirname '{}'执行,然后处理find结果。

顺便说一下,如果从当前目录运行find,这里有一个更好的命令将文件移动到父目录:

find . -name '*.png' -execdir mv {} .. \;

请注意,*.png应该被引用,否则即使在find命令执行之前它也会被shell扩展。