当“ / bin / sh”指向“ / bin / bash”时运行shell脚本


11

我已经在这个问题中阅读以下内容:

bash支持--posix开关,这使其更符合POSIX。如果以sh调用,它也会尝试模仿POSIX 。

上面的引用假设这/bin/sh是指向的链接/bin/bash

但是我不太了解“ sh调用”的含义。


假设我有以下脚本,称为“ script.sh”:

#!/bin/bash
echo "Hello World"

在以下每种情况下,请告诉我该脚本是在普通bash模式下还是在POSIX模式下运行(假设我已经在运行的终端中执行了以下命令bash):

  1. sh script.sh
  2. bash script.sh
  3. ./script.sh

现在说我有以下脚本,称为“ script.sh”(类似于上面的脚本,但没有shebang):

echo "Hello World"

在以下每种情况下,请告诉我该脚本是在普通bash模式下还是在POSIX模式下运行(假设我已经在运行的终端中执行了以下命令bash):

  1. sh script2.sh
  2. bash script2.sh
  3. ./script2.sh

Answers:


19

仅第1和第4种情况将以POSIX模式运行(假定sh是bash而不是sh的其他实现)。任何显式调用no的bash情况--posix都不会,无论是否来自shebang。任何明确调用的情况sh都会。仅当尚未为该脚本显式启动任何外壳程序时,才使用shebang。

情况6,如果您的终端正在运行bash,则不会在POSIX模式下运行,Bash将使用自身调用它。如果你的终端是不是运行的zsh,案例6 同时在POSIX模式下运行。POSIX对于在那种情况下到底应该发生什么一事并不清楚,而Bash和zsh在那里做出了不同的选择。Bash使用自身调用脚本,而zsh使用sh(无论发生什么情况)。其他外壳在这一点上也有所不同。


告诉您处于哪种模式的一种简单方法是使脚本主体:

kill -SIGHUP

在POSIX模式下,它将因错误失败,但会提供kill外部使用说明。这是一个简单的区别,它可以在很多种Bash版本中使用,甚至可以追溯到很久以前。


3
还有其他一些东西将迫使bash以POSIX模式运行,例如POSIXLY_CORRECT环境变量或SHELLOPTS=posix
斯特凡Chazelas

1
[ -o posix ]是一种更明显的方式来检查您是否正在bash中以posix模式运行(不是在其他shell中(除了yash),因此您不想在sh脚本中执行此操作)。POSIXLY_CORRECT=1 bash -c '[ -o posix ] && echo yes'输出yes`
斯特凡Chazelas

2
在情况6中,bash 本身按照POSIX的要求处于POSIX模式时,会以POSIX模式自行调用脚本。POSIX未指定she-bang机制,而6是具有可执行脚本的唯一POSIX方法,并且已明确指定(在POSIX环境中,该脚本应由兼容的sh实用程序解释)。
斯特凡Chazelas

8

“调用为”指的是启动Bash的进程在其“第零个”命令行参数中放入的内容argv[0]

当使用exec*()syscalls启动程序时,他们并没有真正知道包含该程序的二进制文件的名称,而是调用进程可以随意将所需的任何内容放入其中。当然,通常,该名称是从文件系统获取的,因此,如果运行/bin/sh,那就是放在那里。如果/bin/sh是Bash,则不必是符号链接,它可以是硬链接,也可以只是Shell程序的另一个副本。

作为设置“程序名称”的一个示例,Bash的exec命令可以使用该-a选项设置第零个参数。(我们可以用Perl或直接用C等来做同样的事情。)

myname是一个简单的C程序,它仅显示其第零个参数,即它自己看到的名称:

$ ./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外壳或Korn外壳,则同样会看到名称sh,但它以“ SH兼容”模式运行,该模式旨在与Bourne外壳兼容,并且在这两个外壳中均与完全POSIX兼容模式稍有不同。 。
  • 当然,它可以是Almquist壳,实际的Bourne壳或其他东西。

(2&5)运行bash somescript将在常规Bash模式下运行(再次,当然,这取决于bash您所处的PATH状态。)

(3)在此,脚本名称直接代替程序文件提供给系统调用。内核读取hashbang行并使用它来运行脚本。

(6)这是复杂的。它类似于(3),但是ENOEXEC (Exec format error)由于没有hashbang行,用于启动程序的系统调用失败()。接下来发生的情况取决于您所运行的Shell 本身是否处于POSIX模式。POSIX要求POSIX兼容的shell以特定的方式响应ENOEXEC 但是,“等效于调用shell的命令”中存在一些余地,这意味着不同的shell会执行不同的操作。

  • “ Bourne Again”外壳将以脚本名称作为其第一个命令行参数的相同模式重新运行。在符合POSIX的模式下,它当然会以符合POSIX的模式运行,因此遵循POSIX要求来调用符合POSIX的shell。
  • Z shell,Almquist shell和Korn shell /bin/sh以在其他参数之前插入的脚本名称作为第一个命令行参数运行。Z外壳程序,Almquist外壳程序和Korn外壳程序(尝试)通过假定/bin/sh程序是一个来调用符合POSIX的外壳程序。

您能分享这个C程序的源代码
吗?。– GypsyCosmonaut

int main(int argc, char *argv[]){printf("I am %s\n",argv[0]);}
Stig Hemmer

就是这样。
ilkkachu

4

执行的壳是一个叫在命令行或一个在井号(如果命令行没有指定的话)。

因此,版本1和版本4将与一起运行,版本sh2和5将与bash一起运行,而如果您交互使用sh(以及其他一些版本),则版本6和6可能无法运行。Bash确实启动了脚本。Ksh也。Zsh将其启动为sh。

sh如果bash链接到,则只有那些以开头的用户将使用posix选项/bin/sh

将此行添加到脚本中以检测是否正在运行任何bash ksh或zsh版本:

echo "Hello World $BASH_VERSION $KSH_VERSION $ZSH_VERSION"
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.