为什么 bash read 不删除多余的尾随 IFS 字符

为什么 bash read 不删除多余的尾随 IFS 字符

这个命令:

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>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"

你给出了IFS一个值,所以现在你有 2 个字段/列,但你只给出了一个变量来读取,即 a,如果你给出了另一个变量来保存第二个字段

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

mmm a

我不擅长细节,所以有人可以解释更多,但这就是我的理解。

相关内容