while read
するならwhile IFS= read
した方が良いかもよっていう話です。
説明は後にして、まずはlsしたファイル名をechoする例で違いを見てみます。
$ touch " abc " "ho ge" $'\txyz' #3つのファイルを作成します
## 普通にwhile readした場合
$ ls | while read f; do echo "[$f]"; done
[xyz]
[abc]
[ho ge]
## IFS= を付けた場合
$ ls | while IFS= read f; do echo "[$f]"; done
[ xyz]
[ abc ]
[ho ge]
違いは一目瞭然ですね。単にreadをした場合は、前後のタブや空白が全て消えてしまっていますが、IFS= をつけた場合はタブや空白もオリジナルのまま読み込めています。ちなみに ho ge の間は空白2つなんですが中にある空白文字はIFS関係なしにそのまま残ります。
解説
ここで登場したIFS
ってのはbashの環境変数で、デフォルトでは$' ¥t¥n'
(スペース・タブ・改行)が入っています。bashはこれらの文字を単語の区切りとして認識することになっており、結構色んな所で使われている値です。
普段意識することは少ないですが、この存在を忘れているとイリーガルなケースに出会ったときに痛い目を見ることになるので頭の片隅で常に意識しておいたほうが良いでしょう。
さて上記の例の説明ですが、前者の例では前後の半角スペースとタブがIFSに含まれるために消されてしまっています。後者は勝手に文字を消されるのを防ぐためにIFS=
を付けてIFSに空文字を代入した状態でreadを実行させています。そのおかげで変数には無加工の値を得ることが出来ました。
##注意
ちなみに IFS= をやるのは基本 IFS= read foo のようにコマンドの前に付けてコマンドと一緒に実行するようにしておきましょう。
もし普通に IFS= とだけ書いて現在のシェルの変数自体をを変更してしまうと、デフォルトに想定していた挙動が変わってしまうため、色んな部分で想定外の不具合が出てくる可能性がありますので注意です。