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

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-09-09 19:02:08  来源:igfitidea点击:

Why using dirname in find command gives dots for each match?

linuxbashunixfind

提问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 dirnamewith basenamein that command you get the full pathnames. Am I screwing something up here or is this expected behavior? I'm used to basenamegiving you the name of the file (in this case file.ext) and dirnamegiving you the rest of the path.

它只会给你每场比赛的点。当您在该命令中替换为dirnamewithbasename时,您将获得完整的路径名。我在这里搞砸了还是这是预期的行为?我习惯于为basename您提供文件名(在本例中为file.ext),并dirname为您提供路径的其余部分。

采纳答案by Kaleb Pederson

Consider the following script:

考虑以下脚本:

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

set -xshows 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 basenamefor dirname, the expansion still takes places, but the results of the expansion are different:

当你替换basenamedirname,扩展仍然发生,但扩展的结果不同:

  1. pwdis expanded to the current path. In my example above, the result is /home/kibab
  2. basename {}is executed. The result of this command is {}.
  3. 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 '{}' ';'

  1. pwd扩展到当前路径。在我上面的例子中,结果是/home/kibab
  2. basename {}被执行。此命令的结果是{}
  3. 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 -printfand 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 findto execute echo .for each file it finds.

$(dirname {})在传递给find. 这个评估的结果是.,所以你只是告诉find执行echo .它找到的每个文件。

basename {}evaluates to {}, so with $(basename {})substituted for $(dirname {}), findwill 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 dirnamefor 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 findprints paths relative to the path it searches from. If you tried this search from /you would get ``pwd\for each path.

这是因为find打印相对于它搜索的路径的路径。如果您尝试此搜索,/您将获得\每个路径的``pwd 。