![查找:-exec 缺少参数](https://linux22.com/image/36332/%E6%9F%A5%E6%89%BE%EF%BC%9A-exec%20%E7%BC%BA%E5%B0%91%E5%8F%82%E6%95%B0.png)
我正在尝试运行以下命令:
find a/folder b/folder -name *.c -o -name *.h -exec grep -I foobar '{}' +
这是返回一个错误:
find: missing argument to -exec
我看不出这个命令有什么问题,因为它似乎与手册页相匹配:
-执行命令{} +
-exec 选项的这个变体在选定的文件上运行指定的命令,但命令行是通过在末尾附加每个选定的文件名来构建的;该命令的调用总数将远小于匹配文件的数量。命令行的构建方式与 xargs 构建其命令行的方式大致相同。命令中只允许出现一个“{}”实例。该命令在起始目录中执行。
我也尝试过:
find a/folder b/folder -name *.c -o -name *.h -exec grep -I foobar {} +
find a/folder b/folder -name *.c -o -name *.h -exec 'grep -I foobar' {} +
find a/folder b/folder -name *.c -o -name *.h -exec 'grep -I foobar' '{}' +
find a/folder b/folder -name "*.c" -o -name "*.h" -exec grep -I foobar '{}' +
find a/folder b/folder \( -name *.c -o -name *.h \) -exec grep -I foobar '{}' +
find a/folder b/folder -name *.c -o -name *.h -exec grep -I foobar '{}' \+
答案1
您的尝试存在几个问题,包括使用反引号代替引号(在问题的后续编辑中删除)、在需要的地方缺少引号、在无用的地方额外引号、缺少分组子句的括号-o
以及find
使用的不同实现(详情请参阅评论和聊天)。
无论如何,命令可以像这样简化:
find a/folder b/folder -name "*.[ch]" -exec grep -I foobar {} +
或者,如果您使用古老的 GNU find 版本,这应该始终有效:
find a/folder b/folder -name "*.[ch]" -exec grep -I foobar {} \;
答案2
“missing argument to -exec
”通常意味着 - 的参数exec
缺少其终止符。终止符必须是仅包含字符的参数;
(需要在 shell 命令中引用,因此通常写为\;
或';'
),或者是两个包含{}
和 的连续参数+
。
斯蒂芬·查泽拉斯 (Stephane Chazelas) 已确定您正在使用旧版本的 GNU find,它不支持-exec … {} +
, 仅-exec {} \;
.尽管 GNU 是 的较晚采用者-exec … {} +
,但我确实建议您使用不太古董的工具套件(例如西格文,其中包括 git 和更多内容,或者GNUwin32,它缺少 git,但没有 Cygwin 提供的坏员工试图使用 linux-but-we-impose-windows 氛围)。该功能是在 9 年前的 4.2.12 版本中添加的(这是最后一个确定的使 GNU find
POSIX 兼容的功能)。
如果您想坚持使用较旧的 GNU 查找,可以使用-print0
withxargs -0
来获得类似的功能:分组命令执行、支持任意文件名。
find a/folder b/folder -name '*.c' -o -name '*.h' -print0 | xargs -0 grep -I foobar /dev/null
始终在命令行上引用通配符find
。否则,如果您碰巧从包含文件的目录运行此命令.c
,则未加引号的内容将扩展到当前目录中的文件*.c
列表。.c
添加/dev/null
到grep
命令行是确保 grep 始终打印文件名的技巧,即使find
碰巧找到单个匹配项也是如此。对于 GNU find,另一种方法是传递选项-H
。
答案3
如果一个命令如
find a/folder b/folder -name "*.c" -o -name "*.h" -exec grep -I foobar {} +
返回错误
find: missing argument to -exec
可能的原因是 GNU 太旧find
,不支持语法-exec mycommand {} +
。在这种情况下,低性能替换是运行-exec mycommand {} \;
,它将mycommand
为每个找到的目标运行一次,而不是收集多个目标并mycommand
仅运行一次。
然而,GNUfind
不支持例如
find . -type f -and -name "*.ttf" -exec cp {} ~/.fonts +
因为 GNUfind
仅支持文字组合{} +
而不是更通用的{} additional parameters +
。请注意,大括号和字符之间不能有任何内容+
。如果你尝试这样做,你会得到同样的错误:
find: missing argument to -exec
解决方法是使用{} additional parameters \;
确实有效但会为每个找到的目标执行一次命令的语法。如果您需要 GNU 的更高性能,find
则必须编写一个包装脚本,该脚本可以将其他参数附加到给定的参数中。就像是
#!/bin/bash
exec mycommand "$@" additional parameters
应该足够好了。或者,如果您不想创建临时文件,可以使用单行命令更改参数顺序,如下所示:
find . -type f -and -name "*.ttf" -exec bash -c 'mycommand "$@" extra arguments' {} +
这将执行mycommand {list of ttf files} extra arguments
.请注意,您可能需要在标志后面对 bash 的特殊字符进行双重转义-c
。
答案4
过去我曾对 exec 语法感到头痛。现在大多数时候我更喜欢更好的 bash 语法:
for f in `find a/folder b/folder -name "*.[ch]"`; do grep -I foobar $f; done
当您想要将文件视为一个组时,它有一些限制,因为每个文件都是串行评估的,但您可以将输出通过管道传输到其他地方就可以了