zsh在参数扩展后没有按照IFS进行分割

6
这是我的代码,用于循环遍历冒号分隔的值,并对每个值执行某些操作。
f()
{
    IFS=:
    for arg in $1
    do
        echo arg: $arg
    done
}

f foo:bar:baz

这在大多数符合POSIX标准的shell中都可以正常工作。

$ dash foo.sh
arg: foo
arg: bar
arg: baz
$ bash foo.sh
arg: foo
arg: bar
arg: baz
$ ksh foo.sh
arg: foo
arg: bar
arg: baz
$ posh foo.sh
arg: foo
arg: bar
arg: baz
$ yash foo.sh
arg: foo
arg: bar
arg: baz

但是在zsh中,它并没有按照预期的方式工作。
$ zsh foo.sh
arg: foo:bar:baz

这里的zsh是否违反了POSIX标准


1
是的,zsh在这里是故意违反规定的。话虽如此,在任何 shell 中依赖字符串分割都不是一个好习惯——即使在bash中,我也鼓励您使用read -r -a args <<<"$1"或类似的方法读入数组,然后使用for arg in "${args[@]}"; do ... - Charles Duffy
2
这是一个例子,zsh 做了 POSIX 应该做的事情,如果 POSIX 没有尽可能地维护现有行为,那么它就会这样做。作为最糟糕的解决方案,您可以使用 setopt SH_WORD_SPLIT 来恢复 POSIX 的行为。 - chepner
2个回答

3

是的。Zsh已经选择了自己的方式。

这里是zsh faq条目: {{link1:“3.1:为什么$ var,其中var =“foo bar”不做我期望的事情?”}}

在这种特殊情况下,您可以通过将{{link2:-y}}选项添加到zsh调用中来解决问题:

$ zsh -y foo.sh
arg: foo
arg: bar
arg: baz

你��以查看zsh的常见问题,特别是第2章和第3章。你经历过其他shell的越多,你就能发现zsh的缺陷。

2

Zsh中,使用提供的(s)标志(而不是使用IFS)进行分割通常更加简洁。

因此,你的数据解决方案如下:

% f() { for e in ${(s.:.)1}; print $e }
% f foo:bar:baz
foo
bar
baz

请参阅zshexpn(1)手册中的参数扩展部分,了解更多详细信息和相关标志。

(我认为您指的是冒号分隔的值。)


我觉得使用Ruby编写Shell命令脚本还不错...然后我尝试学习更多的Bash和Zsh,但它们对我来说就像火星语一样。 - nonopolarity

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接