为什么在find命令中使用dirname会为每个匹配项添加点数?

时间:2010-03-11 21:00:12

标签: linux bash unix find

我正在使用find来完成任务,我注意到当我做这样的事情时:

find `pwd` -name "file.ext" -exec echo $(dirname {}) \;

它只会为每场比赛提供点数。当您在该命令中使用dirname替换basename时,您将获得完整的路径名。我在这里搞砸了什么或这是预期的行为吗?我习惯basename为您提供文件的名称(在本例中为file.ext),dirname为您提供其余的路径。

7 个答案:

答案 0 :(得分:28)

考虑以下脚本:

#!/bin/sh
set -x
find `pwd` -name "file.ext" -exec echo $(dirname {}) \;

set -x显示扩展如何工作以及最终命令是什么。运行时,它会提供以下输出:

++ pwd
++ dirname '{}'
+ find /home/kibab -name file.ext -exec echo . ';'

所以,扩展的第一件事是pwd。第二个是$(dirname {})。然后将这两个命令的结果放入find命令中。因此,您告诉-exec echo .找到,所以您看到了预期的输出。

当您将basename替换为dirname时,扩展仍然会发生,但扩展的结果会有所不同:

  1. pwd扩展到当前路径。在上面的示例中,结果为/home/kibab
  2. basename {}已执行。此命令的结果为{}
  3. 使用上述替换执行find命令。执行的最终命令如下所示:

    find /home/kibab -name '*.png' -exec echo '{}' ';'

  4. 在检查上面的命令后,您会注意到该命令现在只是回显了找到的任何文件。

    也许你想要这样的东西?

    find `pwd` -name "file.ext" -printf "%f\n"
    

答案 1 :(得分:24)

所以问题是$(...)或`...`在替换之前启动一个新的shell。

考虑使用bash -c:

$ find . -name '*.PNG' -exec bash -c 'git mv {} $(dirname {})/$(basename {} .PNG)48.png' \;

将git repo上的任何图标重命名为更标准的形式。

此处{}在执行任何操作之前被替换,因此问题就消失了。

对于那个例子,TMTOWTDI,但我尽量保持简单,这样你就可以开始你真正需要做的事情了。

答案 2 :(得分:8)

您不必为找到的每个文件调用dirname()。使用GNU find,您可以更快地使用-printf

find /path -type f -iname "*.ext" -printf "%h\n"

答案 3 :(得分:5)

在传递给$(dirname {})之前,

find由shell评估。此评估的结果为.,因此您只是告诉find为找到的每个文件执行echo .

basename {}评估为{},因此$(basename {})替换为$(dirname {})find将为每个文件执行echo {}。这会导致回显每个文件的全名。

如果要为找到的每个文件输出dirname的结果,可以省略echo

find `pwd` -name "file.ext" -exec dirname {} \;

答案 4 :(得分:5)

它显示了点,因为在实际执行命令之前评估了进程替换。因此,您必须将命令传递到单独的shell实例中。

至于解决方法,请使用以下语法:

find $PWD -name "file.ext" -exec sh -c 'echo $(dirname {})' ';'

然而,在每个目录中打印或执行某些内容的最简单方法是-execdir,例如:

find . -name "file.ext" -execdir pwd ';'

答案 5 :(得分:4)

我不知道你为什么会这样做,但试试这个:

find `pwd` -name file.ext |xargs -l1 dirname

答案 6 :(得分:0)

这是因为find打印相对于其搜索路径的路径。如果您从/尝试此搜索,则每条路径都会得到“pwd \