【问题标题】:zsh is not splitting by IFS after parameter expansion参数扩展后 zsh 不被 IFS 拆分
【发布时间】:2017-09-20 05:28:14
【问题描述】:

这是我循环遍历冒号分隔值并执行某些操作的代码 每个值。

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了吗?

【问题讨论】:

  • 是的,zsh 在这里是故意和故意违反的。也就是说,在 any shell 中依赖字符串拆分并不是一个好习惯——即使在 bash 中,我也鼓励您使用 read -r -a args <<<"$1" 或类似的方式读取数组,然后使用 @ 987654326@
  • 这是zsh 做了 POSIX 应该 做的事,它没有尽可能地维护现有行为的负担。作为最糟糕的解决方案,您可以使用setopt SH_WORD_SPLIT 来恢复 POSIX 行为。

标签: bash shell posix zsh ifs


【解决方案1】:

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

这里是 zsh 常见问题条目: “3.1: Why does $var where var="foo bar" not do what I expect?”

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

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

你可以看看the zsh's faq,尤其是第 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) 手册页中的 PARAMETER EXPANSION 部分以了解 更多细节和相关标志。

    (我假设您的意思是 冒号-分隔值。)

    【讨论】:

    • 我觉得使用 Ruby 编写 shell 命令脚本还不错……然后我尝试学习更多 Bash 和 Zsh,但它们对我来说似乎是火星语言
    猜你喜欢
    • 1970-01-01
    • 2022-09-27
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2016-09-07
    • 2011-06-11
    相关资源
    最近更新 更多