为单个语句设置 IFS

Setting IFS for a single statement

在我的 GNU bash, version 4.3.42(1)-release 上,我正在对 做一些测试。这个想法是将一个 : 分隔的字符串及其每个元素拆分成一个数组。

为此,我尝试在命令范围内将 IFS 设置为 :,以便自动拆分并且 IFS 保持不变:

$ myvar="a:b:c"
$ IFS=: d=($myvar)
$ printf "%s\n" ${d[@]}
a
b
c

显然 IFS 保持不变:

$ echo $IFS
                      # empty

BASH reference 说:

If IFS is unset, the parameters are separated by spaces. If IFS is null, the parameters are joined without intervening separators.

但是,然后我注意到 IFS 有点坏了,所以 echo $myvar returns a b c 而不是 a:b:c.

取消设置值解决了它:

$ unset IFS
$ echo $myvar
a:b:c

但我想知道:这是什么原因造成的? IFS=: command 改变 IFS 不只是在正在执行的命令范围内吗?

我在 Setting IFS for a single statement 中看到这确实有效:

$ IFS=: eval 'd=($myvar)'
$ echo $myvar
a:b:c

但我不明白为什么会这样,IFS=: d=($myvar) 不明白。

IFS 在同一行与 read 表现良好:

myvar="a:b:c"
IFS=: read -ra d <<< "$myvar"
printf "%s\n" "${d[@]}"
a
b
c

检查 IFS 的值:

declare -p IFS
-bash: declare: IFS: not found

很明显 IFS 在当前 shell 中没有被篡改。

现在检查原始输入:

echo $myvar
a:b:c

或:

echo "$myvar"
a:b:c

看到你用的时候我就想评论一下,刚才才想起来是什么问题。行

IFS=: d=($myvar)

暂不设置IFS;它只是在当前 shell 中设置两个变量。 (简单命令可以以本地环境设置为前缀,但赋值语句本身不是简单命令。)

写的时候

echo $IFS

IFS扩展为:,但是因为:IFS的第一个字符,所以在分词的时候去掉了。使用

echo "$IFS"

将显示 IFS 仍设置为 :

在bash中,您可以设置一个变量,该变量仅当该语句本身不是变量赋值时才对单个语句有效。例如:

$ foo=one bar=two
$ echo $foo
one

要使第二个赋值成为语句的一部分,您需要...一些其他语句。正如您所注意到的,eval 有效。此外,read 应该有效:

$ foo="one:two:three"
$ IFS=: read -r -a bar <<< "$foo"
$ declare -p bar
declare -a bar='([0]="one" [1]="two" [2]="three")'