这个命令:
read -d 'z' a < <(printf 'a\n\n\n'); printf "$a"
输出:
a
bashread
删除了预期的多余尾随换行符。
并通过将 更改IFS
为空字符:
IFS= read -d 'z' a < <(printf 'a\n\n\n'); printf "$a"
它输出:
a
(blank line)
(blank line)
read
不再删除多余的尾随换行符,因为IFS
不再包含换行符...
但现在如果我们做同样的事情,但用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 空白字符)中,单词开头和结尾处的空白字符、、 和的序列就会被忽略。<newline>
IFS
IFS
space
tab
newline
这种礼貌不适用于非空白字符。您可以使用其他字段拆分实例来检查这一点:
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"
你给出了IFS
一个值,所以现在你有 2 个字段/列,但你只给出了一个变量来读取,即 a,如果你给出了另一个变量来保存第二个字段
IFS=m read -d 'z' a b < <(printf 'ammm'); printf '%s %s' "$b" "$a"
mmm a
我不擅长细节,所以有人可以解释更多,但这就是我的理解。