我已阅读此内容中的以下内容问题:
bash 支持 --posix 开关,这使得它更符合 POSIX 标准。它还尝试模仿 POSIX 如果调用为 sh。
上面的引用假设/bin/sh
是一个指向 的链接/bin/bash
。
但我不太明白是什么意思“作为 sh 调用”。
假设我有以下名为“script.sh”的脚本:
#!/bin/bash
echo "Hello World"
请告诉我在以下每种情况下脚本是否会在正常bash
模式或 POSIX 模式下运行(假设我在正在运行的终端中执行了以下命令bash
):
sh script.sh
bash script.sh
./script.sh
现在假设我有以下名为“script.sh”的脚本(类似于上面的脚本,但没有 shebang):
echo "Hello World"
请告诉我在以下每种情况下脚本是否会在正常bash
模式或 POSIX 模式下运行(假设我在正在运行的终端中执行了以下命令bash
):
sh script2.sh
bash script2.sh
./script2.sh
答案1
只有情况 1 和 4 会在 POSIX 模式下运行(假设是sh
bash 而不是 sh 的其他实现)。任何明确调用bash
without 的情况--posix
都不会,无论是否来自 shebang。任何明确调用 will 的情况sh
。仅当尚未为脚本显式启动 shell 时才使用 shebang。
情况 6,如果您的终端正在运行bash
,则不会以 POSIX 模式运行并且Bash 将使用自身调用它。如果您的终端运行的是 zsh,则情况 6会也运行在 POSIX 模式下。 POSIX 对于在这种情况下到底应该发生什么是不明确的,Bash 和 zsh 在那里做出了不同的选择。 Bash 使用自身调用脚本,而 zsh 使用sh
(无论发生什么情况)。其他 shell 在这一点上也有所不同。
判断您所处模式的一种简单方法是创建脚本主体:
kill -SIGHUP
这将在 POSIX 模式下失败并出现错误kill
,但给出其外部的使用说明。这是一个简单的区别,它适用于很长范围的 Bash 版本,可以追溯到您可能遇到的版本。
答案2
“调用为”指的是启动 Bash 的进程放入其“第零个”命令行参数中的任何内容argv[0]
。
当程序启动时exec*()
系统调用,他们并不真正知道包含程序的二进制文件的名称,而是调用进程可以自由地将其想要的任何内容放在那里。当然,通常情况下,该名称是从文件系统中获取的,因此如果您运行/bin/sh
,那么该名称就会被放在那里。如果/bin/sh
是 Bash,则它不一定是符号链接,它可以是硬链接或只是 shell 程序的另一个副本。
作为设置“程序名称”的示例,Bash 的exec
命令可以使用选项设置第 0 个参数-a
。 (我们可以用 Perl 做同样的事情,或者直接用 C 等)
这里myname
是一个简单的 C 程序,它只打印它的第 0 个参数,即它自己看到的名称:
$ ./myname
I am ./myname
$ (exec -a something ./myname )
I am something
$ mv ./myname somename
$ ln -s somename othername
$ ./somename
I am ./somename
$ ./othername
I am ./othername
来源:
#include <stdio.h>
int main(int argc, char *argv[]) {
printf("I am %s\n", argv[0]);
return 0;
}
但是,要回答编号问题...
(1 & 4) 运行sh somescript
将运行sh
你的任何东西PATH
,可能/bin/sh
但是可能是这样的/usr/xpg4/bin/sh
。
- 如果是 Bash,它会以 POSIX 模式运行,因为它会看到名称
sh
. - 如果它是 Z shell 或 Korn shell,它同样会看到名称
sh
,但它以“SH 兼容”模式运行,该模式旨在兼容 Bourne shell,并且与这两个 shell 中的完整 POSIX 一致模式略有不同。 - 当然,它可能是 Almquist shell、实际的 Bourne shell 或其他东西。
(2 & 5) 运行bash somescript
将以常规 Bash 模式运行(同样,这当然取决于bash
您的PATH
内容。)
(3) 这里,脚本的名称直接提供给系统调用,而不是程序文件。内核读取 hashbang 行并使用它来运行脚本。
(6) 这是一个复杂的问题。它与(3)类似,但是启动程序的系统调用失败(ENOEXEC (Exec format error)
),因为没有 hashbang 行。接下来会发生什么取决于您正在运行的 shell 是否是本身在 POSIX 模式下。POSIX 要求符合 POSIX 的 shell 以特定方式运行以响应ENOEXEC
. 但是,“相当于调用 shell 的命令”存在一些余地,这意味着不同的 shell 会执行不同的操作。
- 谍影重重 shell以相同模式重新运行将脚本的名称作为其第一个命令行参数。在其符合 POSIX 的模式下,它当然会以其符合 POSIX 的模式运行自身,从而遵守调用符合 POSIX 的 shell 的 POSIX 要求。
- Z shell、Almquist shell 和 Korn shell 运行时会
/bin/sh
使用插入在其他参数之前的脚本名称作为其第一个命令行参数。 Z shell、Almquist shell 和 Korn shell(试图)通过假设程序/bin/sh
是符合 POSIX 的 shell 来调用符合 POSIX 的 shell。
答案3
执行的shell是任何一个在命令行中调用的一个或在 shebang 中调用的一个(如果命令行没有指定它)。
因此,版本 1 和 4 将运行sh
,版本 2 和 5 可以使用 bash 运行,版本 6 可以使用不是如果您以交互方式使用 sh (和其他一些),请运行。 Bash 确实启动了脚本。克什也。 Zsh 以 sh 开头。
sh
如果 bash 链接到 ,则只有那些以 as 启动的才会使用 posix 选项/bin/sh
。
将此行添加到您的脚本中以检测是否有任何 bash ksh 或 zsh 版本正在运行它:
echo "Hello World $BASH_VERSION $KSH_VERSION $ZSH_VERSION"