Bash 脚本不适用于 `sh`

HTF*_*HTF 3 scripting bash

我正在测试一个简单的脚本,我想知道为什么从目录执行时它可以正常工作:./test.sh但是当我尝试使用“sh”命令时sh test.sh它不起作用:

test.sh: 3: test.sh: [[: not found
test.sh: 7: test.sh: [[: not found
Run Code Online (Sandbox Code Playgroud)

脚本:

#!/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
Run Code Online (Sandbox Code Playgroud)

Jef*_*and 15

概括

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/[
Run Code Online (Sandbox Code Playgroud)

当您直接通过 执行脚本时./test.sh,您将脚本作为第一行中指定的程序的第一个参数调用。在这种情况下:

#!/usr/bin/env bash
Run Code Online (Sandbox Code Playgroud)

通常,这直接是解释器(/bin/bash,或任何数量的其他脚本解释器),但在您的情况下,您使用 env 在修改后的环境中运行程序 - 但跟随参数仍然是 bash。实际上,./test.shbash test.sh

因为shbash是具有不同语法解释的不同外壳,所以您会看到该错误。如果您运行bash test.sh,您应该会看到预期的内容。

更多信息

其他人在评论中指出/bin/sh可以是链接或其他外壳。从历史上看,sh是旧的 AT&T Unix 上的 Bourne shell,在我看来是规范的下降。但是,这在 BSD 变体中有所不同,并且随着时间的推移在其他基于 Unix 的系统和发行版中有所不同。如果您真的对内部工作原理感兴趣(包括 /bin/sh 和 /bin/bash 如何可以是同一个程序并且行为完全不同),请阅读以下内容:

超级用户:bash 和 sh 有什么区别

维基百科:Bourne shell

  • 此外,sh 并不总是 Bourne shell,但通常意味着与 POSIX sh(主要基于 Bourne)兼容。例如,在 Ubuntu 上,`/bin/sh` 被符号链接到 `/bin/dash`。 (3认同)