Ausführen eines Shell-Skripts, wenn "/ bin / sh" auf "/ bin / bash" zeigt

11

Ich habe in dieser Frage Folgendes gelesen :

bash unterstützt einen --posix-Schalter, wodurch es POSIX-kompatibler wird. Es wird auch versucht, POSIX nachzuahmen, wenn es als sh aufgerufen wird .

Das obige Zitat geht davon aus, dass /bin/shes sich um einen Link handelt, auf den verwiesen wird /bin/bash.

Aber ich verstehe nicht ganz, was unter "als sh angerufen" zu verstehen ist .


Angenommen, ich habe das folgende Skript mit dem Namen "script.sh":

#!/bin/bash
echo "Hello World"

Bitte teilen Sie mir in jedem der folgenden Fälle mit, ob das Skript im normalen bashModus oder im POSIX-Modus ausgeführt wird (vorausgesetzt, ich habe die folgenden Befehle in einem Terminal ausgeführt, das ausgeführt wird bash):

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

Sagen Sie jetzt, dass ich das folgende Skript habe, das "script.sh" heißt (das wie das obige Skript ist, aber ohne den Shebang):

echo "Hello World"

Bitte teilen Sie mir in jedem der folgenden Fälle mit, ob das Skript im normalen bashModus oder im POSIX-Modus ausgeführt wird (vorausgesetzt, ich habe die folgenden Befehle in einem Terminal ausgeführt, das ausgeführt wird bash):

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

Antworten:

19

Nur die Fälle 1 und 4 werden im POSIX-Modus ausgeführt (vorausgesetzt, dies shist Bash und keine andere Implementierung von sh). Jeder Fall, der explizit bashohne ruft, --posixwird nicht, ob vom Schebang oder nicht. Jeder Fall, der explizit aufruft, shwird. Der Shebang wird nur verwendet, wenn noch keine Shell explizit für das Skript gestartet wurde.

Fall 6, wenn Ihr Terminal ausgeführt wird bash, wird nicht im POSIX-Modus ausgeführt und Bash ruft es mit sich selbst auf. Wenn Ihr Terminal zsh ausgeführt wurde stattdessen Fall 6 würde auch im POSIX - Modus. POSIX ist sich nicht sicher, was genau in diesem Fall passieren soll , und Bash und zsh haben dort unterschiedliche Entscheidungen getroffen. Bash ruft das Skript mit sich selbst auf, während zsh es verwendet sh(was auch immer das sein mag). In diesem Punkt variieren auch andere Schalen.


Eine einfache Möglichkeit, um festzustellen, in welchem ​​Modus Sie sich befinden, besteht darin, Ihren Skriptkörper zu erstellen:

kill -SIGHUP

Dies schlägt mit einem Fehler im POSIX-Modus fehl , gibt jedoch Anweisungen zur Verwendung killaußerhalb des POSIX-Modus . Dies ist eine einfache Unterscheidung und funktioniert durch eine Vielzahl von Bash-Versionen, die so weit zurückreichen, wie es wahrscheinlich ist.

Michael Homer
quelle
3
Es gibt andere Dinge, bashdie im POSIX-Modus ausgeführt werden müssen, z. B. die POSIXLY_CORRECTUmgebungsvariable oder SHELLOPTS=posix.
Stéphane Chazelas
1
[ -o posix ]Dies ist eine naheliegendere Methode, um zu überprüfen, ob Sie in Bash im Posix-Modus ausgeführt werden (nicht in anderen Shells (außer Yash), daher möchten Sie dies nicht in einem shSkript tun ). POSIXLY_CORRECT=1 bash -c '[ -o posix ] && echo yes'Ausgaben yes`
Stéphane Chazelas
2
In Fall 6 ruft bash das Skript mit sich selbst im POSIX-Modus auf, wenn es sich selbst im POSIX-Modus befindet, wie es POSIX erfordert. POSIX spezifiziert den She-Bang-Mechanismus nicht und 6 ist die einzige POSIX-Methode, um ausführbare Skripte zu haben, und ist klar spezifiziert (in POSIX-Umgebungen soll das Skript von einem kompatiblen sh-Dienstprogramm interpretiert werden).
Stéphane Chazelas
8

Das "aufgerufen als" bezieht sich auf alles, was der Prozess, der Bash startet, in sein "nulltes" Befehlszeilenargument einfügt argv[0].

Wenn ein Programm mit den exec*()Syscalls gestartet wird, erfahren sie nicht wirklich den Namen der Binärdatei, die das Programm enthält, sondern der aufrufende Prozess kann dort beliebig viel ablegen . Normalerweise wird der Name natürlich aus dem Dateisystem übernommen. Wenn Sie also ausführen /bin/sh, wird dieser dort abgelegt. Und wenn /bin/shes sich um Bash handelt, muss es sich nicht um einen Symlink handeln, sondern um einen Hardlink oder nur um eine weitere Kopie des Shell-Programms.

Als Beispiel für das Setzen des "Programmnamens" kann der execBefehl von Bash das nullte Argument mit der -aOption setzen. (Wir könnten dasselbe mit Perl oder direkt mit C usw. machen.)

Hier mynameist ein einfaches C-Programm, das nur sein nulltes Argument druckt, den Namen, den es selbst sieht:

$ ./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

Quelle:

#include <stdio.h>
int main(int argc, char *argv[]) {
    printf("I am %s\n", argv[0]);
    return 0;
}

Aber um die nummerierten Fragen zu beantworten ...

(1 & 4) Laufen sh somescriptwird laufen, was auch shimmer auf Ihrem ist PATH, wahrscheinlich /bin/shaber möglicherweise so etwas/usr/xpg4/bin/sh .

  • Wenn es Bash ist, wird es im POSIX-Modus ausgeführt, da der Name angezeigt wird sh.
  • Wenn es sich um die Z-Shell oder die Korn-Shell handelt, wird der Name ebenfalls angezeigt, sie shwird jedoch im "SH-kompatiblen" Modus ausgeführt, der darauf abzielt, mit der Bourne-Shell kompatibel zu sein, und sich in beiden Shells geringfügig vom vollständigen POSIX-konformen Modus unterscheidet .
  • Es könnte natürlich die Almquist-Shell sein, eine echte Bourne-Shell oder etwas anderes.

(2 & 5) Das Laufen bash somescriptwird im regulären Bash-Modus ausgeführt (wieder hängt es natürlich davon ab, was sich bashin Ihrem PATHbefindet.)

(3) Hier wird der Name des Skripts anstelle der Programmdatei direkt dem Systemaufruf gegeben. Der Kernel liest die Hashbang-Zeile und verwendet sie zum Ausführen des Skripts.

(6) Dies ist die komplexe. Es ist ähnlich wie (3), aber der Systemaufruf zum Starten des Programms schlägt fehl ( ENOEXEC (Exec format error)), da keine Hashbang-Zeile vorhanden ist. Was als nächstes passiert, hängt davon ab, ob sich die von Ihnen ausgeführte Shell selbst im POSIX-Modus befindet. POSIX erfordert, dass sich eine POSIX-konforme Shell als Reaktion auf eine bestimmte Art und Weise verhält ENOEXEC. Es gibt jedoch einen gewissen Spielraum in "einem Befehl, der dem Aufrufen einer Shell entspricht", was bedeutet, dass verschiedene Shells unterschiedliche Aufgaben ausführen.

  • Die Bourne Again-Shell wird im selben Modus mit dem Namen des Skripts als erstem Befehlszeilenargument erneut ausgeführt. In seinem POSIX-konformen Modus läuft es natürlich selbst in seinem POSIX-konformen Modus und befolgt somit die POSIX-Anforderung, eine POSIX-konforme Shell aufzurufen.
  • Die Z-Shell, die Almquist-Shell und die Korn-Shell werden /bin/shmit dem Namen des Skripts ausgeführt, das vor den anderen Argumenten als erstes Befehlszeilenargument eingefügt wurde. Die Z-Shell, die Almquist-Shell und die Korn-Shell versuchen, eine POSIX-konforme Shell aufzurufen, indem angenommen wird, dass es sich bei dem /bin/shProgramm um eines handelt.
ilkkachu
quelle
Könnten Sie bitte den Quellcode dieses C-Programms teilen ..
GypsyCosmonaut
int main(int argc, char *argv[]){printf("I am %s\n",argv[0]);}
Stig Hemmer
Das wars so ziemlich.
Ilkkachu
4

Die ausgeführte Shell ist entweder die in der Befehlszeile aufgerufene oder die im Shebang aufgerufene (wenn die Befehlszeile dies nicht angibt).

Daher werden die Versionen 1 und 4 mit sh, 2 und 5 mit Bash und 6 möglicherweise nicht ausgeführt, wenn Sie sh (und einige andere) interaktiv verwenden. Bash startet das Skript. Ksh auch. Zsh startet es als sh.

Nur diejenigen, die als gestartet wurden sh, verwenden die Option posix, wenn bash mit verknüpft ist /bin/sh.

Fügen Sie diese Zeile zu Ihrem Skript hinzu, um festzustellen, ob eine bash ksh- oder zsh-Version ausgeführt wird:

echo "Hello World $BASH_VERSION $KSH_VERSION $ZSH_VERSION"
Isaac
quelle