针对空 IFS 测试默认 IFS

针对空 IFS 测试默认 IFS

据我所知,在 Bourne shell 和派生类中,IFS=将 IFS 设置为 null,因此 shell 不会执行任何字段拆分。

我记得读过:

  • echo "$*"
  • IFS= echo "$*"

当我运行这两个命令时,一次在 CentOS 中,一次在 WSL 中(uname -o仅 = GNU/Linux,所以我不知道发行版),我只得到空行。

上面的测试命令是什么意思,这真的是学习 IFS 的好例子吗(如果不是,您会建议什么简单的两行测试)?

答案1

在我回答之前,这里有一个警告:改变IFS往往会产生非常令人困惑的效果。有一些地方它相对安全并且具有明确的效果(例如为命令设置它read,如 和 中IFS= read -r lineIFS=, 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

将其与IFSshell 本身的设置进行对比:

$ 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=("$@"),将它们保存为数组。

相关内容