这是一个简单的测试用例脚本,当我从命令行运行时,它在zsh vs bash中的行为有所不同$ source test_script.sh.我不一定知道为什么有一个区别,如果我的shebang明确表示我希望bash运行我的脚本,而不是which命令是zsh中的内置和bash中的程序.(仅供参考 - shebang目录是我的bash程序所在的地方,可能与你的不一样 - 我使用自制程序安装了新版本)
#!/usr/local/bin/bash
if [ "$(which ls)" ]; then
echo "ls command found"
else
echo "ls command not found"
fi
if [ "$(which foo)" ]; then
echo "foo command found"
else
echo "foo command not found"
Run Code Online (Sandbox Code Playgroud)
我source ./test-script.sh从zsh和Bash 运行这个脚本.
zsh中的输出:
ls command found
foo command found
Run Code Online (Sandbox Code Playgroud)
bash输出:
ls command found
foo command not found
Run Code Online (Sandbox Code Playgroud)
我的理解是,如果字符串不为空/空,则默认为test或[ ](它们是相同的)将字符串计算为true.为了显示:
zsh的:
$ which foo
foo not found
Run Code Online (Sandbox Code Playgroud)
庆典:
$ which foo
$
Run Code Online (Sandbox Code Playgroud)
如果我在zsh中重定向标准错误,如:
$ which foo 2> /dev/null
foo not found
Run Code Online (Sandbox Code Playgroud)
zsh似乎仍然发送foo not found到标准输出,这就是为什么(我猜)我在zshell下传递的测试用例; 因为"$(which xxx)"在两种情况下返回一个字符串的扩展(例如/some/directory和foo not found(zsh总是会返回一个字符串?).
最后,如果我删除双引号(例如$(which xxx)),zsh会给我一个错误.这是输出:
ls command found
test_scritp.sh:27: condition expected not:
Run Code Online (Sandbox Code Playgroud)
我猜zsh想让我用[ ! "$(which xxx)" ].我不明白为什么?它在bash中运行时从未出现过错误(并且不应该在bash中运行吗?!).
为什么我的脚本不使用bash?为什么这样的事情如此微不足道?我理解如何使用该-e选项使其工作正常,但我只是想了解为什么会发生这种情况.它让我疯狂.
这里有两个不同的问题.
首先,使用的正确命令type不是which.就像你注意到的那样,命令which是一个zsh内置命令,而在Bash中,它将执行which你系统上发生的任何命令.有许多具有不同行为的变体,这就是为什么POSIX选择引入替代而不是试图规定特定行为的原因which- 然后还会有一种可能的行为,并且无法轻易地根除所有其他遗留行为.(一个早期的常见问题是使用一个which检查csh环境的命令,即使你实际使用了不同的shell.)
其次,检查命令的输出字符串是一个严重的反模式,因为字符串的语言环境之间的差异("未发现"与"nicht gefunden"与"EIlöytynyt"对等等等等)和程序版本 - 妥善解决是检查命令的退出代码.
if type ls >/dev/null 2>&1; then
echo "ls command found"
else
echo "ls command not found"
fi
if type foo >/dev/null 2>&1; then
echo "foo command found"
else
echo "foo command not found"
fi
Run Code Online (Sandbox Code Playgroud)
(A相关的反模式是检查$?明确.有很少任何必要做这个,因为它是由外壳的流量控制语句自然和透明的,但是像if和while).
关于引用,shell对未加引号的值执行空白标记化和通配符扩展,如果$string是command not found,则表达式
[ $string ]
Run Code Online (Sandbox Code Playgroud)
没有引号围绕值评估
[ command not found ]
Run Code Online (Sandbox Code Playgroud)
它看起来像字符串"命令",然后是一些语法无效的字符串.
最后,正如我们在聊天会话中发现的那样(从评论中链接),OP对其确切含义感到困惑source,并最终在一个单独的进程中运行Bash脚本.(./test-script而不是source ./test-script).对于记录,当您source使用文件时,会导致当前shell读取并执行它; 在这个设置中,脚本的shebang行只是一个注释,并且被shell完全忽略.