为什么在使用选项 + 执行另一个 find 命令时 find 会抱怨

Why find complains when executing another find command with option +

我看过Is it possible to pass a find command to -exec of another find command?但我不明白为什么。
我知道这个问题中的示例命令不是很有用,这只是一个示例命令。


尝试运行以下命令:

$ find -type d -exec find {} -ls + -exec echo {} +
find: Only one instance of {} is supported with -exec ... +

从我的角度来看,打印的错误是不正确的,因为我的命令由两个 -exec 组成,每个都有自己的最终 +

find -type d -exec find {} -ls + -exec echo {} +
             <-----------------> <------------->
                 First command    Second command

仅尝试第一个命令时,出现了不同的错误:

$ find -type d -exec find {} -ls +
find: missing argument to `-exec'
Try 'find --help' for more information.

当然,解决方法是将 + 替换为 \;。但是我想知道为什么我们在上面的两个例子中得到了这些错误信息??? 请提供优雅的解决方案:-)

有关信息,我在 Ubuntu 16.10 和 bash:

上使用 find
$ find --version
find (GNU findutils) 4.7.0-git
Copyright (C) 2016 Free Software Foundation, Inc.
License GPLv3+: GNU GPL version 3 or later <http://gnu.org/licenses/gpl.html>.
This is free software: you are free to change and redistribute it.
There is NO WARRANTY, to the extent permitted by law.

Written by Eric B. Decker, James Youngman, and Kevin Dalley.
Features enabled: D_TYPE O_NOFOLLOW(enabled) LEAF_OPTIMISATION FTS(FTS_CWDFD) CBO(level=2) 

-exec与终结符+一起使用时(与\;相反):

  • 给定的 -exec 操作仅支持占位符 {}
  • 单个 实例
  • 唯一的实例必须放在 last,就在 +.
  • 之前

因此,因为您传递给 -exec ... +find 命令总是需要参数 {} 之后,它无法工作。

换句话说:使用-exec ... +,您不能调用任何要求您传递参数的命令 表示的文件名列表之后 [= =16=].

虽然错误消息可能没有帮助,但这些限制是有充分理由的
由于(依赖于平台的)命令行长度限制,-exec ... + 不能保证 all 文件名可以传递给 single调用指定命令;与 xargs 一样,因此可能必须对列表进行分区以执行 多个 调用(尽可能少)。鉴于这种可能性:如果允许在 {} 之后放置参数,则会出现概念性问题,即在必须进行多次调用的情况下如何处理这些参数(将它们传递给每个调用?只传递给最后一个调用?) ,没有明确的答案。
这些是我自己的推论 - 如果要添加某些内容,请告诉我。

正如您在问题中暗示的那样,这些限制不适用于 -exec ... \;:
的使用 使用终止符 \; 会导致 find 对每个匹配的文件 调用一次命令 ,以便 {} 扩展为 单个 文件名,在这种情况下,您可以在命令的任何位置自由放置 {},可能多次。
相比之下,-exec ... + 导致 find 立即通过(通常)所有 匹配文件名 {} 扩展为文件名 list) 到(通常)单个整体 命令调用。
根据具体的命令,使用 \; 代替 + 可能是一个可行的解决方法,但它具有重要的性能影响:对于大型输入集,差异在创建一个外部进程每个文件名一次和一个单个进程之间将非常明显。


至于错误信息:


$ find -type d -exec find {} -ls + -exec echo {} +
find: Only one instance of {} is supported with -exec ... +

你本意是 two -exec 动作被解析为 one,因为 find 一直在解析直到它发现 {} 紧接着是 +。根据 POSIX specification for find:Thanks, chepner.

Only a <plus-sign> that immediately follows an argument containing only the two characters "{}" shall punctuate the end of the primary expression. Other uses of the <plus-sign> shall not be treated as special.

当解释为单个操作时,它现在包含 2{} 实例,这是不受支持的 +,因此错误消息(总体而言,令人困惑)。


$ find -type d -exec find {} -ls +
find: missing argument to `-exec'

此错误源于 {} 不是终止符 + 之前的 last 参数,这意味着 + 未被识别为动作的 终止符 ,因此整个动作在句法上是无效的。

不幸的是,错误消息令人困惑地表明参数(要执行的命令)是 missing - 将其称为 unterminated 会使更多感觉。