{} \;
と{} \+
と| xargs ...
の機能を正確に知りたい。説明でこれらを明確にしてください。
以下の3つのコマンドが実行され、同じ結果が出力されますが、最初のコマンドには少し時間がかかり、形式も少し異なります。
find . -type f -exec file {} \;
find . -type f -exec file {} \+
find . -type f | xargs file
これは、最初のコマンドがfile
コマンドからのすべてのファイルに対してfind
コマンドを実行するためです。したがって、基本的には次のように実行されます。
file file1.txt
file file2.txt
ただし、後者の2は-exec
コマンドで検索し、以下のようなすべてのファイルに対してfileコマンドを1回実行します。
file file1.txt file2.txt
次に、次のコマンドを実行します。最初のコマンドは問題なく実行されますが、2番目のコマンドではエラーメッセージが表示されます。
find . -type f -iname '*.cpp' -exec mv {} ./test/ \;
find . -type f -iname '*.cpp' -exec mv {} ./test/ \+ #gives error:find: missing argument to `-exec'
{} \+
を含むコマンドの場合、エラーメッセージが表示されます
find: missing argument to `-exec'
何故ですか?誰かが私が間違っていることを説明できますか?
マニュアルページ (または オンラインGNUマニュアル )で、ほとんどすべてが説明されています。
結果ごとに、command {}
が実行されます。 {}
のすべての出現は、ファイル名に置き換えられます。 ;
の先頭にはスラッシュが付き、シェルが解釈できないようにします。
各結果はcommand
に追加され、その後実行されます。コマンドの長さの制限を考慮に入れると、このコマンドがより多く実行される可能性があると思います。
コマンドの呼び出しの総数は、一致するファイルの数よりもはるかに少なくなります。
マニュアルページのこの引用に注意してください。
コマンドラインは、xargsがコマンドラインを作成するのとほぼ同じ方法で作成されます
空白を除いて、{}
と+
の間に文字が許可されないのはそのためです。 +
は、xargs
と同様にコマンドに引数を追加する必要があることをfindに検出させます。
幸いなことに、GNUのmv
実装は、-t
またはより長いパラメーター--target
のいずれかで、ターゲットディレクトリを引数として受け入れることができます。使用方法は次のとおりです。
mv -t target file1 file2 ...
find
コマンドは次のようになります。
find . -type f -iname '*.cpp' -exec mv -t ./test/ {} \+
マニュアルページから:
-execコマンド;
コマンドを実行します。 0ステータスが返された場合はtrue。 findに続くすべての引数は、 `; 'で構成される引数までコマンドの引数とみなされます遭遇します。文字列 `{} 'は、findの一部のバージョンのように、単独の引数だけでなく、コマンドの引数で発生するすべての場所で処理される現在のファイル名に置き換えられます。これらの構造は両方とも、シェルによる展開から保護するために、エスケープする必要があります(「\」で)。 -execオプションの使用例については、使用例セクションを参照してください。指定されたコマンドは、一致したファイルごとに1回実行されます。コマンドは開始ディレクトリで実行されます。 -execアクションの使用を取り巻く避けられないセキュリティ問題があります。代わりに-execdirオプションを使用する必要があります。
-execコマンド{} +
この-execアクションのバリアントは、選択されたファイルに対して指定されたコマンドを実行しますが、コマンドラインは、選択された各ファイル名を最後に追加することによって構築されます。コマンドの呼び出しの総数は、一致するファイルの数よりもはるかに少なくなります。コマンドラインは、xargsがコマンドラインを作成するのとほぼ同じ方法で作成されます。コマンド内では、 `{} 'の1つのインスタンスのみが許可されます。コマンドは開始ディレクトリで実行されます。
Mac OSXでZSHシェルを使用して同じ問題が発生しました。この場合、mv
には-t
オプションがありません。別の解決策を見つけなければなりませんでした。ただし、次のコマンドは成功しました。
find .* * -maxdepth 0 -not -path '.git' -not -path '.backup' -exec mv '{}' .backup \;
秘密は中括弧を引用するでした。 exec
コマンドの最後に中括弧を置く必要はありません。
buntu 14.04(BASHおよびZSH shells)でテストしましたが、同じように動作します。
ただし、+
記号を使用する場合は、exec
コマンドの最後に配置する必要があるようです。
find -iname ... -exec mv -t dest {} +
をサポートしないfind
実装または-iname
をサポートしないmv
実装の-t
と標準的に同等なのは、シェルを使用して引数の順序を変更することです。
find . -name '*.[cC][pP][pP]' -type f -exec sh -c '
exec mv "$@" /dest/dir/' sh {} +
-name '*.[cC][pP][pP]'
を使用することで、現在のロケールに依存して、c
またはp
の大文字バージョンを決定することも避けます。
+
とは対照的に、;
はシェルでは特別ではないため、引用符で囲む必要はありません(引用演算子として\
をサポートしていないrc
のようなシェルを除き、引用は問題ありません)。
/
の末尾の/dest/dir/
は、1つのmv
ファイルのみが見つかり、foo.cpp
が存在しないか、ディレクトリ(またはディレクトリへのシンボリックリンク)でなかった場合に/dest/dir
を/dest/dir
に名前変更する代わりに、エラーでcpp
が失敗するようにします。