findの[ -exec {} \; ]オプション と [ -exec {} + ] オプションがなんなのかメモ

よく人のブログで見かけていた -exec なんちゃらがなにか良くわからなかったので調べた

そもそも-execとは

findの検索結果の結果を渡して別のコマンドを実行するためのもの。
結果xargsと似ている(速度的にはxargsのほうが早いらしいので意味がなければこちらでよさそう)
さらにxargsと同じ処理と思われるのは {} +のほう。

リファレンスを見る

まずは

man find

結果

 -exec utility [argument ...] ;
             True if the program named utility returns a zero value as its exit
             status.  Optional arguments may be passed to the utility.  The expres-
             sion must be terminated by a semicolon (``;'').  If you invoke find
             from a shell you may need to quote the semicolon if the shell would
             otherwise treat it as a control operator.  If the string ``{}''
             appears anywhere in the utility name or the arguments it is replaced
             by the pathname of the current file.  Utility will be executed from
             the directory from which find was executed.  Utility and arguments are
             not subject to the further expansion of shell patterns and constructs.
-exec utility [argument ...] {} +
             Same as -exec, except that ``{}'' is replaced with as many pathnames
             as possible for each invocation of utility.  This behaviour is similar
             to that of xargs(1).

よくわからないのでそのままgoogle翻訳(汗

-execユーティリティ[引数...];
ユーティリティという名前のプログラムが終了するようにゼロの値を返す場合は真
ステータス。オプションの引数は、ユーティリティに渡すことができる。エクスプレッション
(; '' ``)シオンは、セミコロンで終了する必要があります。あなたが見つけ呼び出す場合
シェルからあなたはシェルが希望の場合、セミコロンを引用する必要があるかもしれません
そうでなければ制御演算子として扱う。もし文字列 `` {} ''
ユーティリティ名の任意の場所に表示されるか、引数がそれが交換される
現在のファイルのパス名によって。ユーティリティは以下から実行されます
見つけ、そこからディレクトリが実行されました。ユーティリティと引数は
シェルのパターンと構造物の更なる拡大を受けない。

-execユーティリティ[引数...] {}+
ことを除いて、-execと同じ``{} ''のような多くのパス名に置き換えられます
ユーティリティの各呼び出しのために可能な限り。この動作は似ています
xargsのと(1)。

まずそもそも-exec {} \; のバックスラッシュは;がコマンドか判断がつかないためにエスケープしているだけのよう。
なので意味は無いが-exec {} \+ も有効。

やはり-exec {} + と xargs はリファレンス上も同じということらしい。

動作確認

下記2つは同等の結果となる例。
拡張子がrbのファイルの中で文字列aiueoが含まれるファイルを列挙

-exec {} + 実行

find . -name "*.rb" -exec grep aiueo {} +

xargs 実行

find . -name "*.rb" | xargs grep aiueo

結果はどちらも

./test1.rb:aiueo
./test2.rb:aiueo

※test1,test2どちらもaiueoの文字が含まれているrubyファイル

この状態で
-exec {} \; 実行

find . -name "*.rb" -exec grep aiueo {} \;

結果

aiueo
aiueo

あれ、ファイル名がない・・・・・パスがないのか。これが違い

再度、工夫してチャレンジ
-exec {} + 実行 ※に/dev/nullを指定(複数のファイルが指定された事になる)

find . -name "*.rb" -exec grep aiueo /dev/null {} \;

結果

./test1.rb:aiueo
./test2.rb:aiueo

これでファイル名もでた。

結論

-exec {} + はファイルをまとめて実行する(グループ実行)➡ 全ファイルのパスに置き換えられる
-exec {} \; はファイルを1つずつ実行する(単体実行)➡ファイルパスにならない

ので、ファイル名が欲しい場合は -exec {} + を使うと良い、もっというと速度もあるxargsを使うと良さそう

であってるかな・・・・

ついでに

さらにもっというとmacの場合はmdfindを使うのが一番良い!

さっきの例でいうと

mdfind . -onlyin aiueo

結果

/Users/[user-name]/sample/test1.rb
/Users/[user-name]/sample/test2.rb

親切で便利!そして速い!

その他おすすめの備忘録

Tagged with:
 

コメントを残す