Linux 上的 ZSH 无法识别 shell 脚本中的有效选项
ZSH on Linux doesn't recognize valid options in a shell script
zsh
不识别使用 -o
设置的选项,但 仅当 在 shebang 和 Linux
上时。
以下脚本在 zsh 5.0.2
、zsh 5.6
和最新的 git 上失败:
#!/bin/zsh -o pipefail
thiswillfail | echo 'hello, world'
echo $?
exit
预期输出
hello, world
/home/prajjwal/script:2: command not found: thiswillfail
127
实际输出
/bin/zsh: no such option: pipefail
有效方法
zsh 5.3
上 MacOS Mojave
上的脚本。不过,到目前为止,这似乎在我尝试过的每个 Linux
版本上都失败了。
- 在终端上手动调用
/bin/zsh -o pipefail
- 在脚本中的 shebang 之后
set -o pipefail
设置选项。
我试过的
- 正在清空我的
.zshrc
以确保我的设置不会导致此问题。
一边
虽然我只是想让 pipefail
工作,但它拒绝与我尝试设置的任何其他选项一起工作,即使 zshoptions
中提到了所有这些选项。
这是试图在 #!
行上设置选项的一个陷阱。内核仅在第一个 space.
处拆分 shebang 行
当你说
#!/bin/zsh -o pipefail
最终执行的指令是"/bin/zsh" "-o pipefail" "/home/prajjwal/script"
.
错误消息说 " pipefail"
(注意前导 space)不是有效选项,这是正确的:只有 "pipefail"
有效。
在这种情况下,一个可能的解决方法是将所有内容都塞进一个命令行参数中:
#!/bin/zsh -opipefail
但通常这是不可能的,并且 #!
接口不允许您传递超过一个额外的参数,因此您的选择是找到其他解决方法(例如手动使用 set
)或编写包装器脚本:
#!/bin/zsh
exec /bin/zsh -o pipefail /path/to/the/real/script
在某些系统上还有另一种选择:env -S
。此选项未由 POSIX 指定,并且并非在所有系统上都可用。它适用于 systems using the GNU tools (including all standard Linux distributions) and FreeBSD, but not OpenBSD or NetBSD。我找不到有关 MacOS 的任何信息。
(注意:GNU env 还支持 --split-string
作为替代(长)选项名称,但 FreeBSD env 不支持。)
用法:
#!/usr/bin/env -S /bin/zsh -o pipefail
这会用一个长参数 ('-S /bin/zsh -o pipefail'
) 调用 env
。标准选项处理将其视为 -S
选项后跟参数 (' /bin/zsh -o pipefail'
).
在这样一个简单的例子中,env -S
拆分 spaces/tabs 上的参数并将结果列表视为它首先是原始命令行的一部分:
env -S ' /bin/zsh -o pipefail'
# works the same as:
env /bin/zsh -o pipefail
在不太简单的情况下,您必须引用一些字符(env -S
对待 spaces、"
、'
、\
、$
特别是,等等)。特别是,它 not 像 shell 引用一样工作。有关详细信息,请参阅上面链接的手册页。
zsh
不识别使用 -o
设置的选项,但 仅当 在 shebang 和 Linux
上时。
以下脚本在 zsh 5.0.2
、zsh 5.6
和最新的 git 上失败:
#!/bin/zsh -o pipefail
thiswillfail | echo 'hello, world'
echo $?
exit
预期输出
hello, world
/home/prajjwal/script:2: command not found: thiswillfail
127
实际输出
/bin/zsh: no such option: pipefail
有效方法
zsh 5.3
上MacOS Mojave
上的脚本。不过,到目前为止,这似乎在我尝试过的每个Linux
版本上都失败了。- 在终端上手动调用
/bin/zsh -o pipefail
- 在脚本中的 shebang 之后
set -o pipefail
设置选项。
我试过的
- 正在清空我的
.zshrc
以确保我的设置不会导致此问题。
一边
虽然我只是想让 pipefail
工作,但它拒绝与我尝试设置的任何其他选项一起工作,即使 zshoptions
中提到了所有这些选项。
这是试图在 #!
行上设置选项的一个陷阱。内核仅在第一个 space.
当你说
#!/bin/zsh -o pipefail
最终执行的指令是"/bin/zsh" "-o pipefail" "/home/prajjwal/script"
.
错误消息说 " pipefail"
(注意前导 space)不是有效选项,这是正确的:只有 "pipefail"
有效。
在这种情况下,一个可能的解决方法是将所有内容都塞进一个命令行参数中:
#!/bin/zsh -opipefail
但通常这是不可能的,并且 #!
接口不允许您传递超过一个额外的参数,因此您的选择是找到其他解决方法(例如手动使用 set
)或编写包装器脚本:
#!/bin/zsh
exec /bin/zsh -o pipefail /path/to/the/real/script
在某些系统上还有另一种选择:env -S
。此选项未由 POSIX 指定,并且并非在所有系统上都可用。它适用于 systems using the GNU tools (including all standard Linux distributions) and FreeBSD, but not OpenBSD or NetBSD。我找不到有关 MacOS 的任何信息。
(注意:GNU env 还支持 --split-string
作为替代(长)选项名称,但 FreeBSD env 不支持。)
用法:
#!/usr/bin/env -S /bin/zsh -o pipefail
这会用一个长参数 ('-S /bin/zsh -o pipefail'
) 调用 env
。标准选项处理将其视为 -S
选项后跟参数 (' /bin/zsh -o pipefail'
).
在这样一个简单的例子中,env -S
拆分 spaces/tabs 上的参数并将结果列表视为它首先是原始命令行的一部分:
env -S ' /bin/zsh -o pipefail'
# works the same as:
env /bin/zsh -o pipefail
在不太简单的情况下,您必须引用一些字符(env -S
对待 spaces、"
、'
、\
、$
特别是,等等)。特别是,它 not 像 shell 引用一样工作。有关详细信息,请参阅上面链接的手册页。