有没有一种方法可以逻辑地组合调用的两个 shell 命令查找-执行?
例如打印出所有.csv包含字符串 foo 及其出现次数的文件我想做:
find . -iname \*.csv -exec grep foo {} && echo {} \;
但巴什抱怨“缺少‘-exec’参数”
答案1
-exec
是一个运行命令(不是 shell)并计算结果的谓词真的或者错误的基于命令的结果(零或非零退出状态)。
所以:
find . -iname '*.csv' -exec grep foo {} \; -print
会打印grep
如果在文件中找到 foo,则为文件路径。-print
您可以使用另一个-exec
谓词或任何其他谓词来代替
find . -iname '*.csv' -exec grep foo {} \; -exec echo {} \;
另请参阅!
和-o
查找运算符以获取否定和或者。
或者,您可以启动 shell:
find . -iname '*.csv' -exec sh -c '
grep foo "$1" && echo "$1"' sh {} \;
或者避免为每个文件启动 shell:
find . -iname '*.csv' -exec sh -c '
for file do
grep foo "$file" && echo "$file"
done' sh {} +
答案2
您面临的问题是 shell 首先解析命令行,并看到两个由&&
运算符分隔的简单命令:find . -iname \*.csv -exec grep foo {}
, 和echo {} \;
。引用&&
( ) 会绕过它find . -iname \*.csv -exec grep foo {} '&&' echo {} \;
,但现在执行的命令find
类似于grep
带有参数foo
、wibble.csv
、&&
和echo
。wibble.csv
您需要指示find
运行一个解释该&&
运算符的 shell:
find . -iname \*.csv -exec sh -c 'grep foo "$0" && echo "$0"' {} \;
请注意,后面的第一个参数sh -c SOMECOMMAND
是$0
,不是$1
。
您可以通过将命令调用与-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 {} \;
(我假设grep
和echo
只是为了说明目的,-exec echo
可以用 和 替换-print
,结果输出无论如何都不是特别有用。)
答案3
在这个具体情况下我会这样做:
find . -iname \*.csv -exec grep -l foo \{\} \;
或者如果你有确认:
ack -al -G '.*\.csv' foo
要回答您的实际问题,类似这样的事情可能会起作用:
find . -iname \*.csv -exec sh -c "grep foo {} && echo {}" \;