findコマンドで-execオプションを使用する時の最後の「{} ;」ってなんだっけ?


findコマンドで-execオプションを使用する時の最後の{} ;ってなんだっけ?

私は、-execじゃなく殆どxargsを使ってますが、シェル改修で-execを久々に見ました。
過去、-execオプションも使ってましたが最後の{} ;ってなんだっけ?
と素朴に思いました。
まあ、manを見ろって話なんですが。

findman

man抜粋
-exec command ;
すべてコマンドに対する引き数と見なされる。文字列 `{}` は、
それがコマンドの引き数中に現れるすべての場所で、現在処理中のファイル名に
置き換えられる。

パイプ(|)処理における展開(-)はfind内だと{}になるってことなんですかね。

manを更に読み進めると-exec {} +ってのもあったんですね。

man抜粋
選択したファイルに対して指定したコマンドを実行するが、
コマンドラインを形成するとき、選択した各ファイル名をコマンドラインの末尾に
追加して行くという方法を取る

-exec {} ;-exec {} +の違いは、ググったら1

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

ただし、-exec {} ;よりxargsが推奨みたいですね。
理由は、「find-execでは1つのファイルに対して1回コマンドを実行するが、
xargsならカーネルが許す限り長いコマンドを作って実行するため、
-execよりxargsの方がfork&execの回数が少なくなって効率的なはず」2だそうです。

実際ファイル数が数万個ともなると実行時間に差異が出てくるので分かると思います。

find比較

execxargsとの比較

Terminal
[root@server ~]# time find /var -type f -exec ls -l {} ; > /dev/null
real    0m23.684s
user    0m6.679s
sys     0m15.602s

[root@server ~]# time find /var -type f | xargs ls -l > /dev/null
real    0m0.441s
user    0m0.345s
sys     0m0.160s

キャッシュによる影響確認

明らかにxargsの方が早いですね。
ちなみにキャッシュの関係性もあるかもしれないので
キャッシュをクリア。

Terminal
[root@server ~]# sync && sysctl -w vm.drop_caches=3
[root@server ~]# free
             total       used       free     shared    buffers     cached
Mem:       1034564    1003368      31196          0     123764     761776
-/+ buffers/cache:     117828     916736
Swap:      2031608     107724    1923884
[root@server ~]# sync
[root@server ~]# echo 3 > /proc/sys/vm/drop_caches
[root@server ~]# free
             total       used       free     shared    buffers     cached
Mem:       1034564     240196     794368          0        664     150404
-/+ buffers/cache:      89128     945436
Swap:      2031608     107724    1923884

キャッシュをクリアして何度か実施しましたが
ほぼ、変わらず。

Terminal
[root@server ~]# time find /var -type f | xargs ls -l  > /dev/null

real    0m0.526s
user    0m0.344s
sys     0m0.182s
[root@server ~]# time find /var -type f | xargs ls -l  > /dev/null

real    0m0.443s
user    0m0.326s
sys     0m0.180s

find-lsオプションでは?

ちなみにLinuxではfind-lsというオプションがあるので
同様に計測してみましたが、xargsとほぼ同じ性能でした。

Terminal
[root@server ~]# time find /var -type f -ls > /dev/null

real    0m0.914s
user    0m0.237s
sys     0m0.280s

更にキャッシュクリアしても、あまり差はないですね。

Terminal
[root@server ~]# time find /var -type f -ls > /dev/null

real    0m0.154s
user    0m0.100s
sys     0m0.054s

まあ、スクリプトでそんなにcpmvすることはあっても
大量にlsすることはないんでしょうけど。