bash-私はできる:見つける…-execこの&& that?


23

find-execで呼び出される2つのシェルコマンドを論理的に結合する方法はありますか?

たとえば、文字列fooとその出現を含むすべての.csvファイルを出力するには、次のようにします。

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

しかし、bashは「-execの引数がありません」と文句を言います


2
2 -execを連続して使用することも、単一のを使用することもできます-exec sh -c 'grep foo "$0" && printf %s\\n "$0"' {} \;
jw013

これは繰り返し私をつまずかせました:私は常にsh(この場合{})に渡される最初の引数がのようなものになること$1を期待しています。しかし実際、あなたは正しいです。最初の引数はとして表示されます。最初の引数を呼び出しコマンドの名前にすることは単なる慣習であり、これらのケースでは自動的に強制されません。$0sh$0
-dubiousjim

:たぶん、この質問にマージする必要がありますunix.stackexchange.com/q/18077/4801
dubiousjim

回答:


24

-execコマンド(シェルではなく)を実行し、コマンドの結果(ゼロまたは非ゼロの終了ステータス)に基づいてtrueまたはfalseに評価する述語です。

そう:

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

印刷する場合は、ファイルのパスをgrep発見は、ファイルに狛犬。代わりに、-print別の-exec述語または他の述語を使用できます

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

否定およびorについては、!および-o検索演算子も参照してください。

または、次のようにシェルを起動できます。

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

あなたが直面している問題は、シェルが最初にコマンドラインを解析し、&&演算子で区切られた2つの簡単なコマンドを見るということです:find . -iname \*.csv -exec grep foo {}、およびecho {} \;。引用&&find . -iname \*.csv -exec grep foo {} '&&' echo {} \;)はこれを迂回するが、今で実行されるコマンドは、findのようなものであるgrepの引数を持つfoowibble.csv&&echowibble.csv。演算子findを解釈するシェルを実行するように指示する必要があります&&

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

シェルコマンドは、ちょうど2つのプログラムが区切られている場合&&find書き込み二つの連続:自身で仕事を行うことができます-execアクションを、2つ目は、ステータス0で最初の1が終了した場合に実行されます。

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

(私はgrep、これechoは単に説明のための-exec echoもので-printあり、置き換えることができ、結果の出力はとにかく有用ではないと仮定します。)


2
シェルがエラーメッセージを表示するためにも使用するため、「$ 0」の使用を避ける傾向があります。たとえば、わかりにくい./some-file: grep: command not foundエラーメッセージが表示される場合があります。-exec find sh -c '... "$1"' sh {} \;問題はありません。2番目の検索コマンドにタイプミス(関連)があります。
ステファンシャゼル

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コマンドは、移植できないだけでなく、ファイルパスが最終的にシェルコードとして評価されるため、非常に危険です。
ステファンシャゼル

ack / grepを適切に使用することで、それを試して回避する理由がさらに多くあります:)
Dennis Kaarsemaker

1
この点で、jw013の代替案(質問へのコメントで与えられた)はより安全です。(ジルとステファンの答えが同じテクニックを使用していることに気づいただけです。)
dubiousjim
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.