web-dev-qa-db-ja.com

このbashループでIFS =が行うこと: `cat file | IFS = read -r line;やる...やった `

私はbashを学んでおり、この構造を見ました:

cat file | while IFS= read -r line;
do
    ...
done

誰でも_IFS=は?私はそれが入力フィールドセパレータであることを知っていますが、なぜ何も設定されていないのですか?

23
bodacydo

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=

このバージョンでは、行の内部の空白は保持されます。ただし、先頭と末尾の空白は削除されました。

-rread -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)
50
John1024