神秘 IFS 行为

Mysteries IFS behavior

这里 我了解到我可以通过设置 IFS 将字符串拆分为数组。

这里 我了解到我可以通过 IFS 定界符连接数组。

但在我下面的测试中:

0:~ $ a=(1 2 3)
0:~ $ echo "${a[*]}"
1 2 3
0:~ $ IFS=. echo "${a[*]}" # IFS=. not work
1 2 3
0:~ $ (IFS=.; echo "${a[*]}") # this works
1.2.3
0:~ $ echo $IFS # the original IFS is not change

0:~ $ v=1.2.3
0:~ $ IFS=. b=($v) # change string to array
0:~ $ echo ${b[*]}
1 2 3
0:~ $ echo "${b[*]}" # the array join by `.`!
1.2.3
0:~ $ echo ${b}
1
0:~ $ (IFS=,; echo "${b[*]}") # this still work
1,2,3
0:~ $ IFS=, echo "${b[*]}" # this not work, b array still join by .
1.2.3
0:~ $ c=(1 2 3)
0:~ $ echo "${c[*]}" # a new array join by '.' !
1.2.3
0:~ $ IFS=, echo "${c[*]}" # IFS=, not work, still join by '.'
1.2.3
0:~ $ (IFS=,; echo "${c[*]}") # this works
1,2,3
0:~ $ echo $IFS # original IFS is space

0:~ $ bash --version
GNU bash, version 3.2.57(1)-release (x86_64-apple-darwin18)
Copyright (C) 2007 Free Software Foundation, Inc.

从上面,我有以下guessing/questions:

  1. IFS=. echo "${a[*]}"这改变了回声环境,但没有改变引用扩展环境,所以它不起作用?
  2. 如果 1 为真,为什么 IFS=. b=($v) 成功创建数组?
  3. 为什么 echo "${c[*]}" 加入了 .? IFS 应该是默认的空格。

当您执行 IFS=. b=($v) 两个 shell 赋值时,问题出在 IFS 设置 current shell。将 IFS 修改为 . 将使所有后续的 "${arr[*]}" 类型的数组扩展都使用这个新值。注意这里的双引号,没有引号的相同数组扩展不会使用 IFS${arr[*]}

所以回答你的问题

IFS=. echo "${a[*]}" this change the echo environment, but not change the quoting expanding environment, so it's not work?

你错了,尽管你将 IFS 传递给 echo 接收的环境。但是,echo 不对其环境列表执行任何操作。出现此结果是因为您之前将 IFS 的值设置为 .

if 1 is true, why IFS=. b=($v) successful create the array?

此命令 运行 就像您分别执行这两个命令一样。将IFS修改为.,将不带引号的字符串v的结果展开到分词数组中,值为IFS。由于您之前已将其定义为 .,因此该字符串被拆分为单独的组件并存储到数组中。

why echo "${c[*]}" joined by .? the IFS should be default whitespace.

第一个回答里已经说明了。您已将当前的 shell 修改为使用 IFS.,随后的数组扩展将采用这些来连接字符串。如果您开始新的 shell 和 运行 相同的扩展,它将无法工作。


再澄清一点,即何时将变量传递到命令的本地环境将起作用。如果不是

var=val echo "$var"

如果你写过

var=val sh -c 'echo "$var"'

你看到写的var的值,因为在这种情况下,你在环境中传递var的值,sh shell是运行。但与echo不同的是,sh从环境中读取并看到var的值,并用它来进行变量扩展。