私はbashを学んでおり、この構造を見ました:
cat file | while IFS= read -r line;
do
...
done
誰でも_IFS=
は?私はそれが入力フィールドセパレータであることを知っていますが、なぜ何も設定されていないのですか?
IFS
は多くのことを行いますが、その特定のループについて尋ねています。
そのループの効果は、先頭および末尾の空白を保持する in line
です。説明のために、まずIFSを何も設定しないで観察します。
$ echo " this is a test " | while IFS= read -r line; do echo "=$line=" ; done
= this is a test =
line
変数には、stdinで受け取ったすべての空白が含まれています。次に、デフォルトIFSを使用した同じステートメントを考えます。
$ echo " this is a test " | while read -r line; do echo "=$line=" ; done
=this is a test=
このバージョンでは、行の内部の空白は保持されます。ただし、先頭と末尾の空白は削除されました。
-r
はread -r
で何をしますか?-r
オプションは、read
がバックスラッシュを特殊文字として扱うことを防ぎます。
例として、while
ループに2行を提供する2つのエコーコマンドを使用します。 -r
で何が起こるかを観察します:
$ { echo 'this \\ line is \' ; echo 'continued'; } | while IFS= read -r line; do echo "=$line=" ; done
=this \\ line is \=
=continued=
次に、-r
なしで何が起こるかを観察します。
$ { echo 'this \\ line is \' ; echo 'continued'; } | while IFS= read line; do echo "=$line=" ; done
=this \ line is continued=
-r
がなければ、2つの変更が発生しました。最初に、二重バックスラッシュが単一のバックスラッシュに変換されました。次に、最初の行の末尾のバックスラッシュが行継続文字として解釈され、2行が1行にマージされました。
つまり、入力のバックスラッシュに特別な意味を持たせたい場合は、-r
を使用しないでください。入力のバックスラッシュをプレーン文字として使用する場合は、-r
を使用します。
read
は一度に1行ずつ入力を受け取るため、IFSは複数行入力の各行に影響を与え、単一行入力に影響を与えます。 -r
も同様に動作しますが、-r
がなければ、上記のように末尾のバックスラッシュを使用して複数の行を1行に結合できます。
ただし、複数行入力の動作は、読み取りの-d
フラグを使用して大幅に変更できます。 -d
は、read
が入力行の終わりを示すために使用する区切り文字を変更します。たとえば、行をタブ文字で終了できます。
$ echo $'line one \n line\t two \n line three\t ends here'
line one
line two
line three ends here
$ echo $'line one \n line\t two \n line three\t ends here' | while IFS= read -r -d$'\t' line; do echo "=$line=" ; done
=line one
line=
= two
line three=
ここでは、$'...'
コンストラクトを使用して、改行\n
やタブ\t
などの特殊文字を入力しました。 -d$'\t'
を使用すると、read
は入力をタブ文字に基づいて「行」に分割します。最後のタブ以降は無視されます。
上記の機能の最も重要な使用法は、難しいファイル名を処理することです。パス/ファイル名に表示できない1文字はヌル文字であるため、ヌル文字を使用してファイル名のリストを区切ることができます。例として:
while IFS= read -r -d $'\0' file
do
# do something to each file
done < <(find ~/music -type f -print0)