据我所知,在 Bourne shell 和派生类中,IFS=
将 IFS 设置为 null,因此 shell 不会执行任何字段拆分。
我记得读过:
echo "$*"
IFS= echo "$*"
当我运行这两个命令时,一次在 CentOS 中,一次在 WSL 中(uname -o
仅 = GNU/Linux,所以我不知道发行版),我只得到空行。
上面的测试命令是什么意思,这真的是学习 IFS 的好例子吗(如果不是,您会建议什么简单的两行测试)?
答案1
在我回答之前,这里有一个警告:改变IFS
往往会产生非常令人困惑的效果。有一些地方它相对安全并且具有明确的效果(例如为命令设置它read
,如 和 中IFS= read -r line
)IFS=, read -r field1 field2 field3
,但在我看来,试图理解它的一般行为是比其价值更多的工作。另外,如果您确实更改了它,请通过将分配作为命令的前缀(再次如 中所示)将其隔离到特定命令,IFS= read -r line
或者在您需要更改它之后尽快将其设置回正常状态。
现在的问题是:这些不是很好的IFS
效果示例,首先是因为$*
扩展到当前参数列表,而交互式 shell 通常没有参数,因此它将扩展到空字符串。set
如果需要,您可以使用命令更改它。这是一个例子:
$ echo "$*"
$ set -- "foo bar" "baz/quux"
$ echo "$*"
foo bar baz/quux
其次,因为更改IFS
为特定命令的前缀(如 中所示IFS= echo "$*"
)只会影响该命令运行时的情况,而不会在 shell 扩展其参数时影响(这种情况会发生)前命令本身运行),并且echo
它本身不受影响IFS
(无论IFS
设置为何,它总是将其参数与空格粘在一起)。例如:
$ IFS= echo "$*" # No effect, because IFS is only set for echo, which ignores it
foo bar baz/quux
将其与IFS
shell 本身的设置进行对比:
$ saveIFS=$IFS # Save the normal IFS, so we can set it back later
$ IFS= # Set IFS for the entire shell
$ echo "$*" # Now we'll see an effect
foo barbaz/quux
$ IFS='+-*/' # Let's try another value
$ echo "$*" # Now the arguments get merged, first char of IFS beween them
foo bar+baz/quux
$ echo $* # See below
foo bar baz quux
$ printf '%s\n' $* # See below
foo bar
baz
quux
$ IFS=$saveIFS # Set it back to normal, to avoid trouble later
那么当“+-*/”出现echo $*
时发生了什么?IFS
嗯,IFS
都是用来合并的和分割参数,所以就像 with 一样echo "$*"
,该$*
位扩展为foo bar+baz/quux
,但由于它没有用双引号引起来,所以它立即被分割成单词(使用全部)中的字符IFS
,因此它被分成三个参数echo
:“foo bar”、“baz”和“quux”,然后echo
将它们全部粘在一起,中间有空格。本质上,该命令会发生相同的情况printf
,只是格式字符串使其在单独的行上打印以下每个参数,因此您可以看到“foo bar”只是一个参数。
顺便说一句,有些人使用saveIFS
像我在这里使用的方法,有些人更喜欢unset IFS
之后使用,这使得 shell 起作用仿佛 IFS
恢复到正常的 space-tab-newline 值。两者都有效,但是不在一起。如果您unset IFS
稍后尝试保存并恢复它,它将被设置为空字符串,事情会很奇怪。您还可以使用 显式重置它IFS=$' \t\n'
,但这不能移植到所有 shell(并且会导致真的不支持的 shell 中会出现奇怪的效果$' '
)。叹。
编辑:参见这个问题有关如何保存和恢复 的价值的更多选项和讨论IFS
。
BTW2,在大多数情况下,您不希望参数合并或拆分,所以您想要的是"$@"
.与, 不同的是$*
,$@
它不会合并参数,并且使用双引号时它也不会分割它们(或将它们扩展为文件名通配符)——它只是直接传递它们。但不要使用args="$@"
,因为这实际上确实会像这样合并它们"$*"
(或者可能用“”而不是 的第一个字符IFS
,具体取决于 shell)(它必须合并它们以将它们保存在普通变量中)。而是使用args=("$@")
,将它们保存为数组。