未设置IFS - 意外行为

时间:2016-09-17 10:38:49

标签: linux bash sh

我认为普遍认为unset IFS将IFS恢复为默认值 我找不到以下代码

的原因
echo -n "_${IFS}_" | xxd
IFS=':'
echo -n "_${IFS}_" | xxd
unset IFS
echo -n "_${IFS}_" | xxd
echo "${IFS-IFS is unset}"

返回此

0000000: 5f20 090a 5f                             _ .._
0000000: 5f3a 5f                                  _:_
0000000: 5f5f                                     __
IFS is unset

在我的Ubuntu和Android中 如您所见,IFS实际上是未设置的 提前致谢

3 个答案:

答案 0 :(得分:5)

  

我认为普遍认为未设置IFS会将IFS恢复为默认值。

这是完全错误的,在任何文件中都没有提到这一点!

让我们在the reference manual中搜索IFS,看看我们可以学到什么:

3.4.2 Special Parameters

  

*$*)从1开始扩展到位置参数。当扩展不在双引号内时,每个位置参数都会扩展为单独的单词。在执行它的上下文中,这些单词受到进一步的单词拆分和路径名扩展的影响。当扩展发生在双引号内时,它会扩展为单个单词,每个参数的值由IFS特殊变量的第一个字符分隔。也就是说,$*相当于$1c$2c…,其中cIFS variable值的第一个字符。 如果未设置IFS,则参数以空格分隔。如果IFS为空,则参数将在不插入分隔符的情况下连接。

试一试:

$ set -- one two three
$ IFS=hello
$ echo "$*"
onehtwohthree
$ unset IFS
$ echo "$*"
one two three
$

类似数组的扩展会发生类似的扩展:"${array[*]}""${!prefix*}"

3.5.7 Word Splitting

  

shell将$IFS的每个字符视为分隔符,并将其他扩展的结果拆分为使用这些字符作为字段终止符的单词。 如果IFS未设置,或其值正好为<space><tab><newline>,则默认为,然后是<space><tab>和{{1}的序列在前一个扩展的结果的开头和结尾被忽略,并且任何不在开头或结尾的<newline>个字符序列都用于分隔单词。

也许混淆来自粗体部分。

IFS内置的参考也引用了这一部分,因此我们不会在那里学到任何新东西。 read的其他提及不会给图片带来任何新的东西。

结论

不,取消设置IFS 不会将其重置为默认值。手册中的任何地方都没有提到这一点。令人困惑的是,手册指定,对于单词拆分(以及类似数组的参数的IFS形式),未设置的*产生的行为与默认值{{1 }}

答案 1 :(得分:3)

引用POSIX / http://pubs.opengroup.org/onlinepubs/9699919799/utilities/V3_chap02.html#tag_18_06_05

  

如果 IFS 的值是&lt; space&gt;,&lt; tab&gt;和&lt; newline&gt;,或者它是未设置的,...

这并不意味着取消设置IFS会自动将其重置为IFS。它只是意味着如果您取消设置IFS,则会将" \t\n"设置为IFS,从而完成分词。

答案 2 :(得分:0)

我也看到一些人的帖子说,如果您取消设置IFS,则会将其恢复为默认值。这里的其他答案有助于澄清故事...

在实际使用的基础上,我想补充一点,我没有在 上观察到与op报告相同的在Ubuntu和Droid上的情况。我在Ubuntu 18中针对/bin/sh进行了测试,它按预期工作(就像已将还原还原为空白字符一样)。但是,在Yocto(另一个Linux发行版)上,使用/bin/sh等同于BusyBox(就像您在Droid上找到的一样),unset IFS使其像设置为NULL一样工作,即参数在函数等中接收时,它们之间没有定界符。

为解决这个问题,我定义了一个“常量” DEFAULT_IFS=$' \t\n',并为其分配了IFS,而不是使用unset。该方法对我来说适用于各种情况。