コマンド(command)の出力を各行ずつ取り出して処理したいときに、以下のように while を使って書くことができます:
command | while read line; do
# ここで $line を使う処理を書く
done
xargs よりも見た目に分かりやすいので自分はよく使います[1]。ところが最近、以下のように FFmpeg を使って動画ファイルのエンコードをしようとした際に、この方法には落とし穴があるということに気づきました。
ls /path/to/source/*.mp4 | while read line; do
ffmpeg -i $line # なんやかんや
done
実は FFmpeg は -i で入力ファイルを指定している場合でも、標準入力から読み込むことがあります(参考[2])。そのため上記のような実行方法では ls の出力が FFmpeg に奪われてしまい、正しいファイル名が -i オプションに渡らない場合があります。
つまり、do・done の中には標準入力を奪うコードを書いてはいけません。FFmpeg の場合は(参考リンク先にもあるように) -nostdin をつけると標準入力を使わなくなります。一般的には、必要に応じて < /dev/null をつけてコマンドを実行する必要がありそうです。
注釈
-
このパターンを学んだのは『シェルプログラミング実用テクニック』(上田隆一、技術評論社、2015)だった気がすると思って書籍を引っ張り出してきたところ P.38 付近に言及がありました。 ↩
-
この参考リンクは @[email protected] さんに教えて貰いました。 ↩