理解IFS的默认值

Mar*_*tin 12 shell bash quoting

在我的 GNU bash 版本 4.2.8 中,IFS 默认有空格、制表符和换行符的默认值:

usr@T42 ~ $ echo -n "$IFS" | hexdump -C
00000000  20 09 0a                                          | ..|
00000003
usr@T42 ~ $ 
Run Code Online (Sandbox Code Playgroud)

是否有这种默认 IFS 的原因?此外,除了内置 bash 之外,还有哪些实用程序使用 IFS read

Gra*_*eme 15

每次 shell 执行称为分的任务时,都会使用 IFS 变量。最常见的情况是在$var命令中的参数扩展(例如)或命令替换(例如$(some-command)或已弃用的反引号)之后。这里如果扩展包含任何IFS字符,则在处理命令之前将其拆分为不同的“单词”。实际上,这意味着这些字符将替换文本拆分为不同的参数(如果首先指定了变量,则包括命令的名称)。

因此,默认值为IFS空格、制表符和换行符的原因是这些是通常预期用于拆分单词的空白字符。

防止分词发生的一种方法是在扩展 ( "$var")周围使用双引号- 实际上您已经在问题中做到了这一点。如果你不这样做,就没有输出,echo因为它没有参数,只有字符分割参数。

还要注意,在参数扩展后不会发生分词的两个地方是变量赋值(例如var=$othervarand var=$(somecommand)is ok),以及在[[ ]]构造中([[ $var = $othervar ]]is ok,但[ $var = $othervar ]应该被引用)。

最后,正如一位智者曾经向我指出的那样,一个常见的误解是防止分词是引用变量的唯一原因。事实并非如此,引用还可以防止路径名扩展全局扩展,因为它更广为人知。如果一个变量包含像这样的 glob 字符,*那么当该变量在命令中不加引号使用时,这些字符可能会被扩展为文件名。例如,考虑:

var=*
echo $var
Run Code Online (Sandbox Code Playgroud)

这将显示当前目录中文件的名称。

正如Stephane 在下面指出的那样,展开时字符的顺序IFS很重要"$*"。从bash手册页:

var=*
echo $var
Run Code Online (Sandbox Code Playgroud)

有关分词的更多示例,请参阅此答案 - https://unix.stackexchange.com/a/118444/48083

  • `$IFS` 的第一个字符也用在 `"$*"` 中,这就是顺序很重要的原因。 (2认同)
  • 另请注意,`zsh` 在其默认的 `$IFS` 中包含 NUL 字符(其他 shell 不支持在其变量中保留 NUL 字符)。 (2认同)