bash 为什么在 find 命令中使用 dirname 为每个匹配项提供点?
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/2428628/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
Why using dirname in find command gives dots for each match?
提问by temp2290
I'm using find for a task and I noticed that when I do something like this:
我正在使用 find 进行任务,我注意到当我做这样的事情时:
find `pwd` -name "file.ext" -exec echo $(dirname {}) \;
it will give you dots only for each match. When you substitute dirname
with basename
in that command you get the full pathnames. Am I screwing something up here or is this expected behavior? I'm used to basename
giving you the name of the file (in this case file.ext
) and dirname
giving you the rest of the path.
它只会给你每场比赛的点。当您在该命令中替换为dirname
withbasename
时,您将获得完整的路径名。我在这里搞砸了还是这是预期的行为?我习惯于为basename
您提供文件名(在本例中为file.ext
),并dirname
为您提供路径的其余部分。
采纳答案by Kaleb Pederson
Consider the following script:
考虑以下脚本:
#!/bin/sh
set -x
find `pwd` -name "file.ext" -exec echo $(dirname {}) \;
set -x
shows how the expansion works and what the final command is. When run, it gives the following output:
set -x
显示扩展如何工作以及最终命令是什么。运行时,它提供以下输出:
++ pwd
++ dirname '{}'
+ find /home/kibab -name file.ext -exec echo . ';'
So, the first thing that is expanded is the pwd
. Second is $(dirname {})
. The result of those two commands is then dropped into the find command. Thus, you're telling find to -exec echo .
, so you're seeing the expected output.
因此,首先扩展的是pwd
. 其次是$(dirname {})
。然后将这两个命令的结果放入 find 命令中。因此,您告诉 find 到-exec echo .
,因此您会看到预期的输出。
When you substitute basename
for dirname
, the expansion still takes places, but the results of the expansion are different:
当你替换basename
时dirname
,扩展仍然发生,但扩展的结果不同:
pwd
is expanded to the current path. In my example above, the result is/home/kibab
basename {}
is executed. The result of this command is{}
.The find command is executed with the above substitutions in place. The final command executed looks like this:
find /home/kibab -name '*.png' -exec echo '{}' ';'
pwd
扩展到当前路径。在我上面的例子中,结果是/home/kibab
basename {}
被执行。此命令的结果是{}
。find 命令在执行上述替换的情况下执行。执行的最终命令如下所示:
find /home/kibab -name '*.png' -exec echo '{}' ';'
Upon inspecting the above command, you'll notice that the command now simply echo's whatever file was found.
检查上述命令后,您会注意到该命令现在只是回显找到的任何文件。
Perhaps you want something like this?
也许你想要这样的东西?
find `pwd` -name "file.ext" -printf "%f\n"
回答by albfan
So the problem is that $(...) or `...` starts a new shell before make the replacement.
所以问题是 $(...) 或 `...` 在进行替换之前启动一个新的 shell。
Consider using bash -c:
考虑使用 bash -c:
$ find . -name '*.PNG' -exec bash -c 'git mv {} $(dirname {})/$(basename {} .PNG)48.png' \;
That renames any icon on a git repo to a more standard form.
这会将 git repo 上的任何图标重命名为更标准的形式。
Here {} is replaced before executing anything, so the problem is gone.
这里的 {} 在执行任何操作之前被替换,所以问题消失了。
For that example, TMTOWTDI, but I try to keep it simple so you can start whatever you really need to do.
对于那个例子,TMTOWTDI,但我尽量保持简单,这样你就可以开始你真正需要做的事情。
回答by ghostdog74
you do not have to call dirname() for each file found. with GNU find, you can use -printf
and its faster this way
您不必为找到的每个文件调用 dirname()。使用 GNU find,您可以使用-printf
这种方式并且速度更快
find /path -type f -iname "*.ext" -printf "%h\n"
回答by Phil Ross
$(dirname {})
is evaluated by the shell before being passed to find
. The result of this evaluation is .
, so you're just telling find
to execute echo .
for each file it finds.
$(dirname {})
在传递给find
. 这个评估的结果是.
,所以你只是告诉find
执行echo .
它找到的每个文件。
basename {}
evaluates to {}
, so with $(basename {})
substituted for $(dirname {})
, find
will execute echo {}
for each file. This results in the full name of each file being echoed.
basename {}
计算结果为{}
,因此使用$(basename {})
替代为$(dirname {})
,find
将对echo {}
每个文件执行。这会导致回显每个文件的全名。
If you want to output the result of dirname
for each file found, you can omit the echo
:
如果要输出dirname
找到的每个文件的结果,可以省略echo
:
find `pwd` -name "file.ext" -exec dirname {} \;
回答by kenorb
It showing you the dots, because the process substitution is evaluated before the command is actually executed. So you've to pass your command into separate shell instance.
它向您显示点,因为在实际执行命令之前评估进程替换。所以你必须将你的命令传递到单独的 shell 实例中。
As for workaround, use the following syntax:
至于解决方法,请使用以下语法:
find $PWD -name "file.ext" -exec sh -c 'echo $(dirname {})' ';'
However the easiest way to print or execute something in each directory is by -execdir
, e.g.:
但是,在每个目录中打印或执行某些内容的最简单方法是通过-execdir
,例如:
find . -name "file.ext" -execdir pwd ';'
回答by Paul Tomblin
I don't know why you're getting that, but try this:
我不知道你为什么会得到这个,但试试这个:
find `pwd` -name file.ext |xargs -l1 dirname
回答by pajton
This is because find
prints paths relative to the path it searches from. If you tried this search from /
you would get ``pwd\
for each path.
这是因为find
打印相对于它搜索的路径的路径。如果您尝试此搜索,/
您将获得\
每个路径的``pwd 。