UNIX/Linux の find -exec の引数にはシェルの構文を使えない. | プログラムは楽しげに走らねばならない♪

UNIX/Linux の find -exec の引数にはシェルの構文を使えない.

UNIX/Linux の find コマンドの -exec アクションって,シェルを起動せずに直接コマンドを呼び出すんですね!
今まで知りませんでした (恥).


きっかけは,OKWave でのfind に関する質問.-exec の引数で,シェルの構文 `…`を使うにはどのようにエスケープすればいいのか (私も今までたまに使おうとしては挫折していた) を調べるために find のソースを少しだけ覗いてみると …あれっ,-exec でシェルを起動している気配がない!? 直接コマンドを呼び出しているみたい.それを確認するため,シェルコマンドである alias を -exec に指定して,

  find . -exec alias \;

とやってみると,予想どおり次のようになった.

  find: alias: そのようなファイルやディレクトリはありません
find: alias: そのようなファイルやディレクトリはありません
find: alias: そのようなファイルやディレクトリはありません
(以下略)

やっぱりシェルは呼ばれていない.だから,-execの引数にシェルの構文である `…`などを書いても実行されるわけがない.今まで (たまに) -exec でシェルの構文を使おうとして,エスケープしてみたり,引用符で囲ってみたりと悪戦苦闘してはあきらめてたけど,すべて無駄な努力だったんですね….(ToT)


-exec でシェルの構文を使いたければ,次のようにすれば可能.

  find … -exec bash -c 'シェルコマンド文字列' \;

ただし,ファイルやディレクトリが1つ見つかるたびに毎回シェルが起動されるので遅くなる.さらに,シェルが起動されるたびに ~/.bashrc が実行されてしまうので,これに時間がかかると最悪.


~/.bashrc を実行しないようにするには,次のように bash の代わりにbash へのシンボリックリンクである sh を使えばよい.

  find … -exec sh -c 'シェルコマンド文字列' \;

bash のマニュアルを見ると,sh -c の代わりにbash --norc -c でもいいはずなんだけど,実際やってみると ~/.bashrcが実行されてしまう.なぜ? (?_?)


シェルコマンドも使えて,かつ効率がいいのは,findで一旦シェルスクリプトを作って,それを実行することだろう.-printf を使うと,find で見つけたパス名を加工するのも簡単 (%p,%f,%h,%l など).

  find … -printf "フォーマット文字列" > MyScript.sh
MyScript.sh の内容を確認し,OK ならばそれを実行する.

上記の方法でうまくいくことが確認できれば,次のようにシェルスクリプトの作成と実行を1行で書ける.

  find … -printf "フォーマット文字列" | bash

リンク