find: -exec への引数がありません

find: -exec への引数がありません

次のコマンドを実行しようとしています:

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

これはエラーを返します:

find: missing argument to -exec

このコマンドの何が問題なのかわかりません。マニュアルページと一致しているようです。

-execコマンド{} +

-exec オプションのこのバリエーションは、選択されたファイルに対して指定されたコマンドを実行しますが、コマンドラインは選択された各ファイル名を末尾に追加することによって構築されます。コマンドの呼び出しの合計数は、一致したファイルの数よりもはるかに少なくなります。コマンドラインは、xargs がコマンドラインを構築するのとほぼ同じ方法で構築されます。コマンド内では '{}' のインスタンスは 1 つだけ許可されます。コマンドは開始ディレクトリで実行されます。

私も試しました:

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

「 への引数がありません-exec」は、通常、 - への引数にexec終端子がないことを意味します。終端子は、文字だけを含む引数;(シェル コマンドでは引用符で囲む必要があるため、通常は\;または と記述されます)、またはと';'を含む 2 つの連続した引数である必要があります。{}+

ステファン・シャゼラスはGNU find の古いバージョンを使用しているため、 はサポートされておらず-exec … {} +、 のみをサポートしています-exec {} \;。GNU は を後から採用しましたが-exec … {} +、それほど古くないツールスイート (シグウィン、gitとその他多くのものが含まれています。GNUwin32、git はありませんが、Cygwin のような、Linux を使おうとしているのに Windows を押し付けているような悪い従業員の雰囲気はありません。この機能は、9 年以上前のバージョン 4.2.12 で追加されました (これは、GNU findPOSIX 準拠にするために確認された最後の機能でした)。

古い GNU find を使い続けたい場合、-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/nullコマンドラインに を追加すると、単一の一致が見つかったgrep場合でも grep が常にファイル名を印刷するようにすることができます。GNU find では、別の方法として、オプション を渡すこともできます。find-H

答え3

次のようなコマンドの場合

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

エラーを返す

find: missing argument to -exec

考えられる原因は、find構文をサポートしていない古すぎる GNU です-exec mycommand {} +。その場合、パフォーマンスの低い代替策は、複数のターゲットを収集して を 1 回だけ実行するのではなく、見つかったターゲットごとに を 1 回実行する を-exec mycommand {} \;実行することです。mycommandmycommand

しかし、GNUはfind例えば以下をサポートしていない。

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

GNU はより一般的な ではなく、findリテラルの組み合わせのみをサポートしているためです。中括弧と文字の間には何も入れられないことに注意してください。これを試すと、同じエラーが発生します。{} +{} additional parameters ++

find: missing argument to -exec

回避策としては、{} additional parameters \;機能する構文を使用することですが、見つかったターゲットごとにコマンドを1回実行します。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

ファイルをグループとして扱いたい場合、それぞれが順番に評価されるため、いくつかの制限がありますが、出力を他の場所にパイプすることは問題ありません。

関連情報