bash-我可以做:找到...-执行此&&那吗?


23

有没有一种方法可以逻辑地组合使用find-exec调用的两个shell命令?

例如,要打印出所有包含字符串foo及其出现的.csv文件,我想这样做:

find . -iname \*.csv -exec grep foo {} && echo {} \;

但是bash抱怨“缺少'-exec'的参数”


2
您可以-exec依次使用2 或使用一个-exec sh -c 'grep foo "$0" && printf %s\\n "$0"' {} \;
2012年

这使我反复绊倒:我一直期望传递给sh(在这种情况下{})的第一个参数将是$1并且$0将是sh。但实际上,您是正确的,第一个参数显示为$0。将第一个参数作为调用命令的名称只是一个约定,在这些情况下不会自动执行。
dubiousjim 2012年

也许应该与以下问题合并:unix.stackexchange.com/q/18077/4801
dubiousjim 2012年

Answers:


24

-exec是运行命令(不是外壳程序)并根据命令的结果(零或非零退出状态)评估为truefalse的谓词。

所以:

find . -iname '*.csv' -exec grep foo {} \; -print

如果在文件中找到foo,将打印文件路径grep。代替-print您可以使用其他-exec谓词或任何其他谓词

find . -iname '*.csv' -exec grep foo {} \; -exec echo {} \;

另请参见!-o查找否定运算符和

或者,您可以通过以下方式启动shell:

find . -iname '*.csv' -exec sh -c '
   grep foo "$1" && echo "$1"' sh {} \;

或避免必须为每个文件启动外壳程序:

find . -iname '*.csv' -exec sh -c '
  for i do
    grep foo "$i" && echo "$i"
  done' sh {} +

10

您面临的问题是外壳程序首先解析命令行,然后看到两个由&&操作符分隔的简单命令:find . -iname \*.csv -exec grep foo {}echo {} \;。引用&&find . -iname \*.csv -exec grep foo {} '&&' echo {} \;)绕过,但现在执行的命令find是一样的东西grep的论据foowibble.csv&&echowibble.csv。您需要指示find运行将解释&&操作符的shell :

find . -iname \*.csv -exec sh -c 'grep foo "$0" && echo "$0"' {} \;

请注意,第一个参数后sh -c SOMECOMMAND$0不是$1

通过将命令调用与分组,可以为每个文件节省Shell进程的启动时间-exec … +。为了便于加工,通过一些虚拟的价值$0,使"$@"枚举的文件名。

find . -iname \*.csv -exec sh -c 'for x in "$@"; do grep foo "$x" && echo "$x"; done' \ {} +

如果shell命令只是两个由分隔的程序&&,则find可以自己完成该工作:编写两个连续的-exec动作,而第二个动作只有在第一个动作以状态0退出时才会执行。

find . -iname \*.csv -exec grep foo {} \; -exec echo {} \;

(我认为grepecho只是出于说明的目的,-exec echo可以替换为,-print并且最终的输出也不是特别有用。)


2
我倾向于避免为此使用“ $ 0”,因为外壳程序也使用它来显示错误消息。例如,您可能会看到一个令人困惑的./some-file: grep: command not found错误消息。-exec find sh -c '... "$1"' sh {} \;不会有问题。您的第二个find命令中有一个错字(相关)。
斯特凡Chazelas

3

在这种情况下,我会这样做:

find . -iname \*.csv -exec grep -l foo \{\} \;

或者,如果您有ack

ack -al -G '.*\.csv' foo

要回答您的实际问题,可能需要执行以下操作:

find . -iname \*.csv -exec sh -c "grep foo {} && echo {}" \;


3
后一个find命令不仅是不可移植的,而且非常危险,因为文件路径最终被评估为shell代码。
斯特凡Chazelas

所有更多的理由尝试通过正确使用ack / grep来避免它:)
Dennis Kaarsemaker 2012年

1
在这方面,jw013的替代方案(在对问题的评论中给出)更安全。(只是注意到吉尔斯和斯蒂芬的答案使用了相同的技术。)
dubiousjim 2012年
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.