zsh環境でシェルスクリプトでforループを書くとき、ある点に注意しないと予期しない動作になります。結構ハマる箇所だと思ったので注意点をメモしておきます。
※なお、bash環境では修正前のやり方でも問題なく動くようです(ご指摘ありがとうございます!)。
find
コマンドを使うと、特定の名前のディレクトリやファイルをリストアップすることができます。
jpgファイルをリストアップするコマンド
find . -name "*.jpg" -type f
とすれば、カレントディレクトリ内の.jpg
拡張子を持つファイルのリストを取得することができます。例えば今、このコマンドの出力が以下のようであったとします。
上記コマンドを実行した結果
./image-5.jpg
./image-2.jpg
./image-0.jpg
./image-4.jpg
./image-6.jpg
./image-9.jpg
./image-8.jpg
./image-1.jpg
./image-3.jpg
./image-10.jpg
./image-7.jpg
さて、これをfor文で回してみましょう(以下のコードは失敗例)。
for文で結果をループ(失敗例)
files=`find . -name "*.jpg" -type f`
for file in $files; do
echo $file
done
出力結果
./image-5.jpg
./image-2.jpg
./image-0.jpg
./image-4.jpg
./image-6.jpg
./image-9.jpg
./image-8.jpg
./image-1.jpg
./image-3.jpg
./image-10.jpg
./image-7.jpg
できてそうな気がしますよね。でも、本当かな?
echo $file
のあとにecho "---------"
と区切りを入れてみましょう。
for文で結果をループ(失敗例の挙動確認)
files=`find . -name "*.jpg" -type f`
for file in $files; do
echo $file
echo "---------"
done
出力結果
./image-5.jpg
./image-2.jpg
./image-0.jpg
./image-4.jpg
./image-6.jpg
./image-9.jpg
./image-8.jpg
./image-1.jpg
./image-3.jpg
./image-10.jpg
./image-7.jpg
---------
区切り文字列が最後にしか出力されていませんね。forループは1回しか走っていないようです。
では、どうしたらいいのか。答えは簡単です。
外側に丸括弧をつければ、リストとして認識され意図していた通りの挙動になります。
()で囲ってリストにする
files=(`find . -name "*.jpg" -type f`)
./image-5.jpg
---------
./image-2.jpg
---------
./image-0.jpg
---------
./image-4.jpg
---------
./image-6.jpg
---------
./image-9.jpg
---------
./image-8.jpg
---------
./image-1.jpg
---------
./image-3.jpg
---------
./image-10.jpg
---------
./image-7.jpg
---------
正しく反復できていますね。