晴耕雨読

working in the fields on fine days and reading books on rainy days

find -exec でパイプを使った複数コマンドを実行する

find -exec の中でパイプを使って複数コマンドを実行する方法について説明します。

パイプを使った実行例

ここでは、カレントディレクトリ以下にあるファイルの中身を全て小文字にするコマンドを書くことを例に説明していきます。 一つのファイルだけであれば、次のコマンドでできます。

cat input.txt | tr 'A-Z' 'a-z' > input.txt.lower

これをそのまま、find -exec で実行しようとしても上手く動きません。

# 動かない例
find . -type f -name '*.txt' -exec cat {} | tr 'A-Z' 'a-z' > {}.lower \;

原因は -exec の後ろには1つのコマンドしか取れないからです。

find でパイプを使う方法

代わりに、sh -c "実行したいコマンド" と書くことで複数のコマンドを一つのコマンドにまとめることで動くようになります。

find . -type f -name '*.txt' -exec sh -c "cat {} | tr 'A-Z' 'a-z' > {}.lower" \;

パイプの処理を関数に置き換える方法

もしシェルスクリプトを書いているなら、あえてワンライナーにする必要はないと思います。 複数のコマンドを一つのコマンドにまとめるという点で関数を使う方法があります。

tolower() {
    cat "$1" | tr 'A-Z' 'a-z' > "$1".lower
}
find . -type f -name '*.txt' -exec tolower {} \;

findの結果をfor文で回す方法

その他に挙げるとすれば、-exec を使わないで for-in を使う方法もあります。

for file in $(find . -type f -name '*.txt'); do
    cat "$file" | tr 'A-Z' 'a-z' > "$file".lower
done

以上です。