查找:-exec缺少参数


18

我正在尝试运行以下命令:

find a/folder b/folder -name *.c -o -name *.h -exec grep -I foobar '{}' +

这将返回错误:

find: missing argument to -exec

我看不到此命令出了什么问题,因为它似乎与手册页匹配:

-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 '{}' \+

您是否尝试过转义+find a/folder b/folder -name *.c -o -name *.h -exec grep -I foobar '{}' \+
jayhendren 2014年

3
您可能正在使用旧版本的GNU find。尽管该-exec cmd {} +变体是POSIX,并且自80年代就已经可用,但是GNU发现(相对)只是最近才添加了它(2005年)。是什么find --version告诉你吗?
斯特凡Chazelas

2
@Koveras,那就是这样。-exec {} +是在2005年的4.2.12中添加的。在较早的GNU发现中,您可以使用(非POSIX)-print0 | xargs -r0获得类似的内容。4.1是从1994
StéphaneChazelas 2014年

1
JRFerguson指出(在已删除的答案中),-name应该将模式参数引用为:-name "*.c" -o -name "*.h"。这是正确的,尽管它与-exec错误无关。您会注意到,所有其他答案都将通配符放在引号中,尽管只有Gilles提及了它。…(续)
G-Man说'Resstate Monica''19

1
(续)…jlliagre的回答折叠了名称表达式,-name "*.[ch]"没有任何解释。这样的好处是简化了命令行,特别是消除了  -o。查找涉及-o的表达式很难正确。你错了 如果您的命令是固定的,因此不会出错(如Gilles的回答),它将grep仅在.h文件上运行。你需要做'(' -name '*.c' -o -name '*.h' ')'
G-Man说'Resstate Monica''Mar

Answers:


18

您需要删除在中使用的单引号{}。该命令可以这样简化:

find a/folder b/folder -name "*.[ch]" -exec grep -I foobar {} +

如果您使用过时的GNU查找版本,则该版本仍然可以正常工作:

find a/folder b/folder -name "*.[ch]" -exec grep -I foobar {} \;

糟糕,它们是引号,而不是反引号。
大卫·肯尼迪

引号将毫无用处,因为{}对shell没有特定的含义。
jlliagre 2014年

在查找手册页中:“字符串'{}'被替换为在命令参数中出现的所有处所正在处理的当前文件名,而不仅仅是在find的某些版本中,单独存在的参数中。可能需要对结构进行转义(带有'\')或加引号,以防止它们被外壳扩展。”
戴维·肯尼迪

1
我确实在手册页中读到了该内容,但事实是我所知道的没有外壳,因此需要引用大括号。您正在使用什么外壳?
jlliagre 2014年

重击。无论是否使用引号,我都会收到错误消息。
大卫·肯尼迪

10

“缺少”的参数-exec通常意味着-的参数exec缺少其终止符。终止符必须是仅包含字符的参数;(需要在shell命令中加引号,因此通常用\;或编写';'),或者是两个连续的包含{}和的参数+

Stephane Chazelas确定您使用的是GNU find的旧版本-exec … {} +,仅不支持-exec {} \;。尽管GNU是的较晚采用者-exec … {} +,但我还是建议您使用较不老式的工具套件(例如Cygwin,其中包括git和更多的工具,或者GNUwin32,它缺少git但没有不良员工的经验。 -可以使用Cygwin提供的Linux,但我们可以设置Windows氛围)。此功能是在9年前的4.2.12版本中添加的(这是使GNU findPOSIX兼容的最后确定的功能)。

如果要坚持使用较旧的GNU查找,可以使用-print0with xargs -0获得类似的功能:分组命令执行,支持任意文件名。

find a/folder b/folder -name '*.c' -o -name '*.h' -print0 | xargs -0 grep -I foobar /dev/null

始终在find命令行上引用通配符。否则,如果您恰巧在包含.c文件的目录中运行此命令,则未引用的文件*.c将被扩展到.c当前目录中的文件列表。

添加/dev/nullgrep命令行是确保grep始终打印文件名的一种技巧,即使find碰巧找到一个匹配项也是如此。使用GNU find,另一种方法是传递option -H


1
cygwin给出的坏员工尝试使用linux,但我们施加Windows氛围是什么意思?
大卫·肯尼迪

GNUwin32没想到:(
David Kennedy

请参阅我对这个问题的评论。
G-Man说'Resstate Monica''19

在package.json脚本中使用半引号引起来。
bvj

2

如果命令如

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一次。

但是,GNU find不支持例如

find . -type f -and -name "*.ttf" -exec cp {} ~/.fonts +

因为GNU find仅支持文字组合,{} +而不支持更通用的组合{} 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。请注意,您可能需要在-c标志后面为bash的转义特殊字符加倍。


(1)上面实际回答问题的部分已经由其他人给出。(2)您所描述的不是GNU的缺陷或不足find,而是POSIX指定的正确行为。
G-Man说'Resstate Monica''Mar

1
+1最后,有人回答为什么其他参数不起作用!似乎在POSIX定义中存在不足。
乔纳森

如果您有GNU,find那么您可能已经有了GNU cp。在这种情况下,您可以find ... -exec cp --target-directory ~/.fonts {} +将保留{}在执行字符串的末尾。
roaima

1

find . -type f -perm 0777 -exec chmod 644 {}\;

出错了find: missing argument to ``-exec'

在它们之间添加空间{}\修复它:

find . -type f -perm 0777 -print -exec chmod 644 {} \;


1
当前问题中的find命令中没有这样的问题。
库萨兰达

在Question中,我理解不是很好,但是问题是相同的“ find:缺少“ -exec”的参数”,问题可能是由于不同的2个原因引起的,我回答是因为我看到了相同的问题陈述。
ShreePool

@Kusalananda感到非常悲伤,菜鸟为报告的错误提供了解决方案,该错误由OP在问题的标题和正文中说明。
bvj

@bvj该问题明确涉及+-exec选项形式find。该答案正在纠正提出该问题的用户所没有的问题。
库萨兰达

-1

过去,我对exec语法感到头痛。现在大多数时候,我更喜欢更好的bash语法:

for f in `find a/folder b/folder -name "*.[ch]"`; do grep -I foobar $f; done

当您希望将文件作为一组对待时,它有一些限制,因为每个文件都是按顺序求值的,但是您可以将输出通过管道传输到其他位置


1
尽管这种方法很有效,但是它比纯查找版本的实用性要差得多,因为它不能正确处理名称中带有空格的文件。
伊坦·赖斯纳

5
不,不要这样做。一旦文件包含空格和其他“怪异”字符,此操作就会中断。这也比复杂和慢find … -exec … \;,因此即使您知道文件名驯服也没有理由使用它。
吉尔(Gilles)'所以

这对我需要基于文件名运行多行逻辑的情况很有帮助(例如删除字符,创建目录然后移动文件)。在exec我想花5分钟的时间里,试图找到一个可以同时做多个事情的方法实在令人头疼。我的文件名很温和,这解决了我的问题:)
gMale
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.