未设置IFS - 意外行为

Cla*_*dio 6 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}"
Run Code Online (Sandbox Code Playgroud)

返回此

0000000: 5f20 090a 5f                             _ .._
0000000: 5f3a 5f                                  _:_
0000000: 5f5f                                     __
IFS is unset
Run Code Online (Sandbox Code Playgroud)

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

gni*_*urf 7

我认为普遍同意将unset IFS恢复IFS为默认值.

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


让我们IFS参考手册中搜索,看看我们可以学到什么:

3.4.2特殊参数

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

试试吧:

$ set -- one two three
$ IFS=hello
$ echo "$*"
onehtwohthree
$ unset IFS
$ echo "$*"
one two three
$
Run Code Online (Sandbox Code Playgroud)

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

3.5.7单词拆分

shell将每个字符$IFS视为分隔符,并使用这些字符作为字段终止符将其他扩展的结果拆分为单词.如果IFS没有设置,或者它的值是完全<space><tab><newline>,默认值,然后序列<space>,<tab>以及<newline>在开始和以前扩张的结果最终会被忽略,而任何序列IFS在开始时没有字符或结束用于分隔单词.

也许混淆来自粗体部分.

为参考read内置指的是这一部分也是如此,所以我们不会学到什么新东西.其他提及IFS不会带来任何新的东西.


结论.

不,解封IFS其重置为默认值.手册中的任何地方都没有提到这一点.混淆来自于手册指定,对于单词拆分(以及*类似数组的参数的形式),未设置IFS产生与默认值相同的行为IFS.


Buv*_*inJ 7

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

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

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


mel*_*ene 5

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

如果IFS 的值为 <space>、<tab> 和 <newline>,或者未设置,...

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