セミコロン(;)とプラス(+)をexecで検索で使用する


159

使用すると出力に違いがあるのはなぜですか

find . -exec ls '{}' \+

そして

find . -exec ls '{}' \;

私は得ました:

$ find . -exec ls  \{\} \+
./file1  ./file2

.:
file1  file2  testdir1

./testdir1:
testdir2

./testdir1/testdir2:


$ find . -exec ls  \{\} \;
file1  file2  testdir1
testdir2
./file2
./file1

回答:


249

これは例で最もよく示されるかもしれません。レッツ・発言find、これらのファイルをアップになります:

file1
file2
file3

-execセミコロン(find . -exec ls '{}' \;)で使用すると、実行されます

ls file1
ls file2
ls file3

しかし、代わりにプラス記号(find . -exec ls '{}' \+)を使用する場合、できるだけ多くのファイル名が単一のコマンドの引数として渡されます。

ls file1 file2 file3

ファイル名の数は、システムの最大コマンドライン長によってのみ制限されます。コマンドがこの長さを超える場合、コマンドは複数回呼び出されます。


1
ありがとう。これは、結果のファイルをソートする場合に非常に便利です。find-maxdepth 1 -type f -mtime -1 -exec ls -ltr {} \ +
fbas

1
ばかばかしいq:私は、+関連付けられたもの-execは常にエスケープさ+-mtimeていますが、関連付けられたものはエスケープされていません。その理由を知っていますか?に;関連して脱出する習慣があると思い-execます。
kevinarpe 2018年

3
@kevinarpe確かに、私は癖になるようにチョークで書き;ます。脱出する必要があることを想像することはできません+
マーティン

36

これまでの答えはすべて正解です。私はこれを、私ではechoなく、以下を使用して記述された動作のより明確な(私にとっての)デモとして提供しますls

セミコロンを使用すると、echo見つかったファイル(または他のファイルシステムオブジェクト)ごとにコマンドが呼び出されます。

$ find . -name 'test*' -exec echo {} \;
./test.c
./test.cpp
./test.new
./test.php
./test.py
./test.sh

プラスの場合、コマンドechoは一度だけ呼び出されます。見つかったすべてのファイルは引数として渡されます。

$ find . -name 'test*' -exec echo {} \+
./test.c ./test.cpp ./test.new ./test.php ./test.py ./test.sh

find多数の結果が表示される場合は、呼び出されているコマンドが引数の数に詰まることがあります。


1
結果をシェルに安全に渡すことができる数だけに結果を追加しないでください。少なくとも何をxargsしているの か...原則として、あまりにも多くの議論が詰まることはありません。
Rmano 2013年

1
@Rmano:Solarisでfind(そしてxargs)消費するよりも多くの引数を出力するのを見てきました。GNUのfindutils`xargs(およびfind)はより賢く動作するようですが、誰もがGNUを使用しているわけではありません。
Johnsyweb 2013年

2
@Johnsyweb、すべてのPOSIX findは引数の数が上限に達しないようにしています。そして、これにはSolaris(少なくとも10)が含まれます。失敗する可能性があるのは、find ... -exec ksh -c 'cmd "$@" "$@"' sh {} +またはのようなことをした場合ですがfind ... -exec ksh -c 'files="$*" cmd "$@"' sh {} +、それfindについては本当に非難することはできません。GNU findfindサポートする最後の実装の1つであったことに注意してください+(これまでは、GNUシステムにスクリプトを移植するのは面倒でした)。
ステファンChazelas

18

からman find

-execコマンド;

コマンドを実行します。0ステータスが返された場合はtrue。次のfindの引数はすべて、「;」で構成される引数まで、コマンドの引数と見なされます。遭遇した。文字列 '{}'は、findの一部のバージョンのように、それが単独の引数だけでなく、コマンドの引数で発生するすべての場所で処理されている現在のファイル名に置き換えられます。これらの構造は両方とも、シェルによる拡張から保護するために、エスケープ(「\」を使用)または引用符で囲む必要がある場合があります。「-exec」オプションの使用例については、使用例のセクションを参照してください。指定されたコマンドは、一致したファイルごとに1回実行されます。 コマンドは、開始ディレクトリで実行されます。-execオプションの使用に関する避けられないセキュリティ問題があります。

-execコマンド{} +

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

だから、私はそれを理解する方法は、\;で見つかった各ファイルに対して別々のコマンドを実行しfind、一方、\+ファイルを追加し、それらのすべてに単一のコマンドを実行します。\それはですので、エスケープ文字であります:

ls testdir1; ls testdir2 

ls testdir1 testdir2

私のシェルで上記を行うと、質問の出力がミラーリングされました。

使用したい場合の例 \+

2つのファイルがある1.tmpとし2.tmpます。

1.tmp:

1
2
3

2.tmp:

0
2
3

\;

 find *.tmp -exec diff {} \;
> diff: missing operand after `1.tmp'
> diff: Try `diff --help' for more information.
> diff: missing operand after `2.tmp'
> diff: Try `diff --help' for more information.

一方、\+(の結果を連結するため)を使用する場合find

find *.tmp -exec diff {} \+
1c1,3
< 1
---
> 0
> 2
> 30

したがって、この場合にはそれが違いだdiff 1.tmp; diff 2.tmpdiff 1.tmp 2.tmp

\;適切\+で必要な場合があります。\+withの使用rmはそのようなインスタンスの1つであり、多数のファイルを削除する場合、パフォーマンス(速度)はよりも優れてい\;ます。


manページも読むことができます。私はそうしましたが、を使用することの違いを理解していないと思います。vs +
アンクルアガルワル

私は-1が公平だったとは思わない、私は男の私の理解を説明した。私はただ男をコピーして去っただけではありませんでした。しかし、より良い例を含むように私の回答を編集しました。
11

10

find特別な構文があります。{}見つかったファイルのパス名として検索する意味があり、(ほとんどの)シェルはそれらを別の方法で解釈しないため、そのままを使用します。\;セミコロンはシェルにとって意味があるため、バックスラッシュが必要findです。したがってfind、Cプログラムに渡される引数リストで、シェルが実行された後に確認したいのは、

「-exec」、「rm」、「{}」、「;」

ただし\;、コマンドラインで、シェルから引数までセミコロンを取得する必要があります。

あなたが離れて得ることができる\{\}のシェル引用された解釈があるため\{\}だけです{}。同様に、「{}」を使用できます。

あなたがすることはできませんやっていることは、使用されます

 -exec 'rm {} ;'

シェルはそれを1つの引数として解釈するため、

「-exec」、「rm {};」

そしてrm {} ;、コマンドの名前ではありません。(少なくとも誰かが本当にねじ回していない限り。)

更新

違いは

$ ls file1
$ ls file2

そして

$ ls file1 file2

+コマンドライン上に名をcatenatingています。


1
あなたの言っていることが理解できます。使用の違いを教えてください。vs +
Ankur Agarwal

1
申し訳ありませんが、私の質問またはコメントを注意深く読みましたか?言い換える必要があるかもしれません。findでexecを使用してセミコロンを使用した場合と、findでexecでplusを使用した場合のo / pが異なるのはなぜですか?
Ankur Agarwal、

2
これはなぜコマンドがこのようなものであるかについての優れた説明であり、受け入れられた答えはカバーしていません。ありがとう!
Sherwin Yu

1

;(セミコロン)または+(プラス記号)の違いは、引数がfindの-exec/ -execdirパラメーターに渡される方法です。例えば:

  • using ;は複数のコマンドを実行します(引数ごとに個別に)、

    例:

    $ find /etc/rc* -exec echo Arg: {} ';'
    Arg: /etc/rc.common
    Arg: /etc/rc.common~previous
    Arg: /etc/rc.local
    Arg: /etc/rc.netboot
    

    以下のすべてのfind引数は、コマンドの引数と見なされます。

    文字列{}は、処理中の現在のファイル名に置き換えられます。

  • using +は、可能な限り最小限のコマンドを実行します(引数が結合されるため)。これはxargscommandの動作と非常に似ているため、コマンドごとにできるだけ多くの引数を使用して、1行あたりの引数の最大数を超えないようにします。

    例:

    $ find /etc/rc* -exec echo Arg: {} '+'
    Arg: /etc/rc.common /etc/rc.common~previous /etc/rc.local /etc/rc.netboot
    

    コマンドラインは、選択した各ファイル名を最後に追加することによって構築されます。

    {}コマンド内で許可されるのは1つのインスタンスのみです。

以下も参照してください。


-5

ハウスキーピング用のファイルを見つけようとしていました。

見つける。-exec echo {} \; コマンドは結果的に夜通し実行されました。

見つける。-exec echo {} \ +結果があり、数時間しかかかりませんでした。

お役に立てれば。


2
この回答は、これらの2つの方法がどのように機能するか、およびそれらによって生成される結果がどのように異なるかを説明していません。
misko321
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.