find -exec mv {} ./target/ +が機能しないのはなぜですか?


98

私は正確に何を知りたい{} \;{} \+して| 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つのfind -execコマンドは、以下のようなすべてのファイルに対してfile commandを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'

何故ですか?誰かが私が間違っていることを説明できますか?


本当の質問は簡単です、なぜ最初のものはうまくいき、2番目のものはうまくいかないのですか?(1)検索。-type f -iname ' .cpp' -exec mv {} ./test/ \; (2)見つける。-type f -iname ' .cpp' -exec mv {} ./test/ \ +
Shahadat Hossain

回答:


185

マニュアルページ(またはオンラインGNUマニュアルは)ほとんどすべてを説明します。

find -exec command {} \;

結果ごとに、command {}が実行されます。のすべての出現{}箇所はファイル名に置き換えられます。;シェルが解釈しないように、スラッシュが前に付きます。

find -execコマンド{} +

各結果はcommand後に追加されて実行されます。コマンドの長さの制限を考慮に入れると、このコマンドがさらに実行される可能性があり、マニュアルページが私をサポートしていると思います:

コマンドの呼び出しの総数は、一致したファイルの数よりもはるかに少なくなります。

マニュアルページからのこの引用に注意してください:

コマンドラインは、xargsがコマンドラインを構築するのとほぼ同じ方法で構築されます。

そのため、空白の間{}+除いて空白文字以外の文字は許可されません。+と同様にコマンドに引数を追加する必要があることをfindに検出させますxargs

ソリューション

幸いなことに、の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つだけ使用できます。コマンドは、開始ディレクトリで実行されます。


1
実際にどのように機能するかはわかっています。このマニュアルを何度か読みましたが、{} +を使用しても、{} +を使用するとエラーメッセージが表示されます。WindowsでCygwinを使用しています。
Shahadat Hossain

1
@Shahadat:「マニュアルページから」の前の部分を読みましたか?との./test/間に配置しましたが、これらの間に空白以外の文字は許可されていません。{}+
Lekensteyn 2011

ruは、。/ test /を{}と+の間に入れないでください。次に、mvコマンドがどのように機能するか。mvには、{}であるソースと./test/である宛先が必要で、+で終了します。あなたは正しいと思うコマンドを書いてもらえますか?
Shahadat Hossain

@Shahadat:あなたが達成しようとしていることがわかります。Windowsはプログラムの実行が遅いため、1つのコマンドにまとめたいと考えています。答えに代替を追加します。
Lekensteyn

1
この+コマンドはファイルを「最後」に貼り付けるため(そしての代わりにではない{}ため)、少し奇妙なAFAIU {}です。なぜ使用するのか、これは混乱を招きます。-t私が知らなかったオプションのおかげで、オプションはその-exec +問題の回避策として作成されたようです!
e2-e4 2017年

6

Mac OSXZSHシェルを使用して同じ問題が発生しました。この場合はの-tオプションがないためmv、別の解決策を見つける必要がありました。ただし、次のコマンドは成功しました。

find .* * -maxdepth 0 -not -path '.git' -not -path '.backup' -exec mv '{}' .backup \;

秘密は中括弧を引用することでした。括弧がexecコマンドの最後にある必要はありません。

Ubuntu 14.04BASHシェルとZSHシェルを使用)でテストしましたが、同じように動作します。

ただし、+記号を使用する場合は、execコマンドの最後に配置する必要があるようです。


{}ニーズがで引用するfishと、rcシェルではなくでzshbashもBourneまたはcshの家族の他のシェル。
ステファンChazelas

@StephaneChazelasうん、Ubuntuの下でで再テストされましたbash。確かに引用符は必要ありません。奇妙なことに、MacOSで(を使用してzsh)引用しないと問題が発生しました。しかし、Macが
手元に

3

サポートしていない実装またはサポートしていない実装のfind -iname ... -exec mv -t dest {} +for の標準的な同等物は、シェルを使用して引数を並べ替えることです。find-inamemv-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/それはそうであるmv代わりに、名前変更のエラーで失敗foo.cppする/dest/dir唯一の場合にcppファイルが見つかったと/dest/dir存在しなかったか、ディレクトリ(またはディレクトリへのシンボリックリンク)はなかったです。


+1 ...コマンドを実行するための予備としてのシェル内操作は、実際にはさまざまなユースケースで役立ちます...いいですね。
Cbhihe

0
find . -name "*.mp3" -exec mv --target-directory=/home/d0k/Музика/ {} \+

他の人がそれから学ぶことができるように、あなたの答えにいくつかの説明を加えてください
ニコ・ハーセ

説明を求めた質問に答える必要があります。コードのみは答えではありません。
Lajos Arpad

-1

いいえ、違い+とは\;逆にする必要があります。 +execコマンドの最後にファイルを追加してから、execコマンドを\;実行し、ファイルごとにコマンドを実行します。

問題は 、それをエスケープしたり、終了したりする必要find . -type f -iname '*.cpp' -exec mv {} ./test/ \+find . -type f -iname '*.cpp' -exec mv {} ./test/ +ないことです。+

xargs私は長い間使用していませんが、+のように機能すると思います。


私もこれを試しましたが、同じエラーメッセージが表示されました。さらに、どこでも+だけを使用することがわかりましたが、cygwinでは\ +または "+"を使用しないと動作しません。
Shahadat Hossain

これはcygwin環境です。申し訳ありませんが、よくわかりません。cygwinシェルは使用していません。* nixを使用しています。
マイクラミレス

1
@Shahadat Hossainは-name "*.cpp"、-iname '??? work。* \
Mike Ramirez

1
@マイク:私はあなたの誤解との違いだと思う-iname-name-inameの大文字と小文字を区別しないバージョンで-nameあり、正規表現の処理に違いはありません。投稿する前にコマンドを試すことをお勧めします。あなたのコマンドも私のシェルで失敗します。
Lekensteyn 2011

1
@Lekensteynそれはあなたのコメントの前に事実であったことはすでに確立されていました。私はあなたの投稿の前にShahadatを認めていたと思いました、それは単純な「大丈夫」でした。いいえ、手動では実行しませんでした。頭の上から実行しましたが、そのような正規表現検索をfindで使用することはほとんどありません。それは単なる「力助け」タイプのものでした。
マイクラミレス
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.