find コマンドを使っていると、いつも -exec オプションの書き方をググってしまうので、いったんキチンと理解します。
man find を読んで理解を深める
{} \; って何だ?
find の man を読むと、 -exec の項目は、以下のように書かれています。
-exec utility [argument ...] ;
以下、man を対訳していきます。
True if the program named utility returns a zero value as its exit status.
utility という名前のプログラムが終了ステータスとしてゼロ値を返す場合は True です。
ふむふむ。
Optional arguments may be passed to the utility. The expression must be terminated by a semicolon (“;”)
utility にはオプションの引数を渡すことができます。式はセミコロン(";")で終了する必要があります。
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.
シェルから find を呼び出す場合、シェルが制御演算子として処理しないように、セミコロンを引用符で囲む必要があります。
なるほど。シェルの制御演算子として解釈されないように、セミコロンの前にバックスラッシュを付けて記述するんですね。
そもそも意味がわかってなかったので、引用符で囲んでもよい、というのは知りませんでした。
末尾のセミコロンは以下のどちらで記述しても大丈夫。
find . -type f -exec ls -l {} \;
find . -type f -exec ls -l {} ';'
そして、 {}
について。
If the string “{}” appears anywhere in the utility name or the arguments it is repaced by the pathname of the current file.
utility名または引数のどこかに文字列 “{}” がある場合は、現在のファイルのパス名に置き換えられます。
{}
は find コマンドで得られたファイルが展開されるプレースホルダーになっているということですね。
このあたりは、もともと認識していた内容と一致していました。
{} + ってのもあるぞ
その次の項目に、 以下のような見出しがありました。
-exec utility [argument ...] {} +
末尾が +
になってます。
これも man を訳してみると…
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).
-exec と同じですが、utility の呼び出しごとに “{}” が可能な限り多くのパス名に置き換えられます。この動作は xargs(1) の動作に似ています。
find コマンドで得られたファイルが、 -exec で指定されたコマンドラインの末尾にどんどん追加されていくイメージですね。
使い方など
{}
が複数あっても大丈夫なので、ファイル名のリネームとかに使えますね。
例1) ファイル名の末尾に接尾辞 .bak をつける。
find . -type f -exec mv {} {}.bak \;
複数コマンドをパイプで繋げるときは、 sh -c
で括ってあげます。ちゃんと {}
が展開されるから不思議。
例2) 逆に末尾の .bak を取り除く
find . -type f -exec sh -c 'mv {} `echo {} | sed -e "s/\.bak$//"`' \;