我正在测试一个简单的脚本,我想知道为什么它从目录执行时运行良好:./test.sh
但是当我尝试使用“sh”命令时sh test.sh
它不起作用:
test.sh: 3: test.sh: [[: not found
test.sh: 7: test.sh: [[: not found
脚本:
#!/usr/bin/env bash
if [[ $1 = one ]]
then
printf "%b" "two\n" >&2
exit 0
elif [[ $1 = two ]]
then
printf "%b" "one\n" >&2
exit 0
else
printf "%b" "Specify argument: one/two\n"
exit 1
fi
答案1
概括
sh
是与 不同的程序bash
。
细节
问题在于 Bourne shell ( sh
) 不是 Bourne Again shell ( bash
)。也就是说,sh 无法理解该[[
指令。事实上,它[
也无法理解。[
是一个实际的程序或指向 /bin/test(或 /usr/bin/[, /usr/bin/test)的链接。
$ which [
/bin/[
$ ls -lh /bin/[
-r-xr-xr-x 2 root wheel 42K Feb 29 17:11 /bin/[
当您直接通过 执行脚本时./test.sh
,您会将脚本作为第一行指定的程序的第一个参数来调用。在本例中:
#!/usr/bin/env bash
通常,这直接是解释器(/bin/bash
,或任何其他脚本解释器),但在您的情况下,您使用 env 在修改后的环境中运行程序 - 但后续参数仍然是 bash。实际上,./test.sh
是bash test.sh
。
由于sh
和bash
是不同的 shell,具有不同的语法解释,因此您会看到该错误。如果您运行bash test.sh
,您应该会看到预期的结果。
更多信息
其他人在评论中指出,/bin/sh
可以是链接或其他 shell。从历史上看,sh
是旧 AT&T Unix 上的 Bourne shell,在我看来是规范的后裔。然而,这在 BSD 变体中有所不同,并且随着时间的推移,在其他基于 Unix 的系统和发行版中也出现了分歧。如果您真的对内部工作原理感兴趣(包括 /bin/sh 和 /bin/bash 如何成为同一个程序并表现完全不同),请阅读以下内容:
答案2
如上所述:/bin/sh 通常(但并非总是)调用符合 POSIX 标准的 Bourne shell。Bash 不是 Bourne。
当以“sh”调用时(例如当 /bin/sh 符号链接或链接到 /bin/bash 时),或者当在调用环境中定义 $POSIXLY_CORRECT 时,当使用 --posix 调用选项调用时,或者当执行了“set -o posix”时,Bash 将尝试模拟 Bourne。这可以测试 Bourne shell 脚本/命令是否符合 POSIX 标准。
或者,使用已知的 POSIX 兼容 shell 调用脚本/测试命令。'dash' 很接近,Korn shell (ksh) IIRC 也提供了兼容 POSIX 的选项。