我正在使用find来完成任务,我注意到当我做这样的事情时:
find `pwd` -name "file.ext" -exec echo $(dirname {}) \;
它只会为每场比赛提供点数。当您在该命令中使用dirname
替换basename
时,您将获得完整的路径名。我在这里搞砸了什么或这是预期的行为吗?我习惯basename
为您提供文件的名称(在本例中为file.ext
),dirname
为您提供其余的路径。
答案 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
时,扩展仍然会发生,但扩展的结果会有所不同:
pwd
扩展到当前路径。在上面的示例中,结果为/home/kibab
basename {}
已执行。此命令的结果为{}
。使用上述替换执行find命令。执行的最终命令如下所示:
find /home/kibab -name '*.png' -exec echo '{}' ';'
在检查上面的命令后,您会注意到该命令现在只是回显了找到的任何文件。
也许你想要这样的东西?
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 \
。