bash読み取りが追加の末尾のIFS文字を削除しないのはなぜですか?

bash読み取りが追加の末尾のIFS文字を削除しないのはなぜですか?

このコマンドは次のとおりです。

read -d 'z' a < <(printf 'a\n\n\n'); printf "$a"

出力:

a

bashはread予想される追加の末尾の改行を削除しました。

そしてnull文字IFSに変更。

IFS= read -d 'z' a < <(printf 'a\n\n\n'); printf "$a"

次のように出力されます。

a 
(blank line)
(blank line)

readIFS改行文字が含まれなくなったため、追加の末尾の改行文字は削除されません。

しかし、今同じことをしますが、m代わりに改行文字を使用すると、次のようになります。

IFS=m read -d 'z' a < <(printf 'ammm'); printf "$a"

出力は次のとおりです。

a

ただし、実際の出力は次のようになります。

ammm

readつまり、追加の末尾IFS文字(この場合はm文字)は削除されません。

なぜ?

答え1

フィールド分割は、特に先行および後続 IFS スペースを無視します。 ~からGNU Bashマニュアル、3.5.7トークン化:

設定されていIFSない場合、またはその値がデフォルト値の場合<space><tab><newline>、前の拡張結果の先頭と末尾にある、およびのシーケンスは無視され、<space>開始<tab>または終了以外の文字シーケンスは単語を区切るために使用されます。デフォルト以外の値を使用すると、スペース文字はIFS値(IFSスペース文字)にある1つの単語の先頭と末尾にあるスペース文字シーケンス、、、およびを無視します。<newline>IFSIFSspacetabnewline

この例は、空白以外の文字には適用されません。別のフィールド分割インスタンスを使用してこれを確認できます。

bash-5.0$ printf "|%s|\n" $(printf '\n\na\nb\n\n')
|a|
|b|
bash-5.0$ IFS=' '; printf "|%s|\n" $(printf '  a b  ')
|a|
|b|
bash-5.0$ IFS=z; printf "|%s|\n" $(printf 'zzazbzz')
||
||
|a|
|b|
||

答え2

デフォルトでは、読み取りでは先行/学習スペースと改行文字が削除されます。 IFSを追加するとデフォルト値があるため、読み取り時にその値は削除されません。

あなたの例では

IFS=m read -d 'z' a < <(printf 'ammm'); printf "$a"

値を提供したので、IFS2つのフィールド/列がありますが、読み取る変数は1つだけ提供しました。つまり、2番目のフィールドを保持するために別の変数を指定した場合です。

IFS=m read -d 'z' a b < <(printf 'ammm'); printf '%s %s' "$b" "$a"

mmm a

私が詳細を理解していないので、誰がより詳細に説明することができますが、これは私が理解したものです。

関連情報