Exécution d'un script shell lorsque «/ bin / sh» pointe sur «/ bin / bash»

11

J'ai lu ce qui suit dans cette question :

bash prend en charge un commutateur --posix, ce qui le rend plus compatible POSIX. Il essaie également d'imiter POSIX s'il est appelé en tant que sh .

La citation ci-dessus suppose qu'il /bin/shs'agit d'un lien pointant vers /bin/bash.

Mais je ne comprends pas très bien ce que l'on entend par "invoqué comme sh" .


Disons que j'ai le script suivant qui s'appelle "script.sh":

#!/bin/bash
echo "Hello World"

Veuillez me dire dans chacun des cas suivants si le script sera exécuté en bashmode normal ou en mode POSIX (supposez que j'ai exécuté les commandes suivantes dans un terminal en cours d'exécution bash):

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

Maintenant, disons que j'ai le script suivant qui s'appelle "script.sh" (qui est comme le script ci-dessus mais sans le shebang):

echo "Hello World"

Veuillez me dire dans chacun des cas suivants si le script sera exécuté en bashmode normal ou en mode POSIX (supposez que j'ai exécuté les commandes suivantes dans un terminal en cours d'exécution bash):

  1. sh script2.sh
  2. bash script2.sh
  3. ./script2.sh
user269904
la source

Réponses:

19

Seuls les cas 1 et 4 s'exécuteront en mode POSIX (en supposant que shc'est bash et pas une autre implémentation de sh). Tout cas qui appelle explicitement bashsans --posixvolonté, que ce soit du shebang ou non. Tout cas qui appelle explicitement le shsera. Le shebang n'est utilisé que lorsqu'aucun shell n'a déjà été explicitement démarré pour le script.

Le cas 6, si votre terminal est en cours d'exécution bash, ne fonctionnera pas en mode POSIX et Bash l'invoquera en utilisant lui-même. Si le terminal était en cours d' exécution au lieu zsh, 6 cas serait également exécuter en mode POSIX. POSIX est ambigu quant à ce qui devrait se passer dans ce cas , et Bash et zsh y ont fait des choix différents. Bash invoque le script en utilisant lui-même, tandis que zsh l'utilise sh(quel qu'il soit). D'autres obus varient également sur ce point.


Une façon simple de savoir dans quel mode vous êtes est de créer votre corps de script:

kill -SIGHUP

qui échouera avec une erreur en mode POSIX , mais donnera des instructions d'utilisation pour l' killextérieur. C'est une distinction facile et cela fonctionne à travers une longue gamme de versions de Bash remontant aussi loin que vous êtes susceptible de rencontrer.

Michael Homer
la source
3
Il y a d'autres choses qui forceront bashà s'exécuter en mode POSIX comme la POSIXLY_CORRECTvariable d'environnement ou SHELLOPTS=posix.
Stéphane Chazelas
1
[ -o posix ]est un moyen plus évident de vérifier que vous exécutez en mode posix dans bash (pas dans d'autres shells (sauf yash), donc vous ne voudriez pas le faire dans un shscript). POSIXLY_CORRECT=1 bash -c '[ -o posix ] && echo yes'sorties yes`
Stéphane Chazelas
2
Dans le cas 6, bash appelle le script avec lui - même en mode POSIX quand il est lui - même en mode POSIX exige POSIX. POSIX ne spécifie pas le mécanisme she-bang, et 6 est le seul moyen POSIX d'avoir des scripts exécutables et est clairement spécifié (dans les environnements POSIX, le script est destiné à être interprété par un utilitaire sh conforme).
Stéphane Chazelas
8

Le « invoqué comme » fait référence à quoi que ce soit que le processus de démarrage Bash met dans son argument de ligne de commande « zeroth », argv[0].

Lorsqu'un programme est démarré avec les exec*()appels système , ils ne connaissent pas vraiment le nom du fichier binaire contenant le programme, mais à la place, le processus d'appel est libre d'y mettre ce qu'il veut. Habituellement, bien sûr, le nom est tiré du système de fichiers, donc si vous exécutez /bin/sh, c'est ce qui est mis là. Et si /bin/shc'est Bash, il ne doit pas nécessairement être un lien symbolique, il peut s'agir d'un lien dur ou simplement d'une autre copie du programme shell.

Comme exemple de définition du "nom du programme", la execcommande de Bash peut définir l'argument zéro avec l' -aoption. (On pourrait faire de même avec Perl, ou directement avec C, etc.)

Voici mynameun programme C simple qui affiche simplement son argument zéro, le nom qu'il voit lui-même:

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

La source:

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

Mais, pour répondre aux questions numérotées ...

(1 & 4) en cours d'exécution sh somescriptexécutera tout ce qui se shtrouve sur votre PATH, probablement /bin/shmais peut-être quelque chose comme/usr/xpg4/bin/sh .

  • S'il s'agit de Bash, il s'exécute en mode POSIX, car il voit le nom sh.
  • S'il s'agit du shell Z ou du shell Korn, il voit également le nom sh, mais il fonctionne en mode "SH compatible", qui vise à être compatible avec le shell Bourne et est subtilement différent du mode conforme POSIX complet dans ces deux shells. .
  • Ce pourrait être le shell Almquist, un véritable shell Bourne, ou autre chose, bien sûr.

(2 & 5) La course bash somescriptse déroulera en mode Bash normal (encore une fois, cela dépend bien sûr de ce que bashvous PATHêtes.)

(3) Ici, le nom du script est donné directement à l'appel système à la place du fichier programme. Le noyau lit la ligne de hachage et l'utilise pour exécuter le script.

(6) C'est le complexe. Il est similaire à (3), mais l'appel système pour démarrer le programme échoue ( ENOEXEC (Exec format error)), car il n'y a pas de ligne de hachage. Ce qui se passe ensuite dépend de si le shell que vous exécutez est lui - même en mode POSIX. POSIX requiert qu'un shell conforme à POSIX se comporte d'une manière spécifique en réponse à ENOEXEC. Cependant, il existe une certaine marge de manœuvre dans "une commande équivalente à l'invocation d'un shell", ce qui signifie que différents shells font des choses différentes.

  • Le shell Bourne Again se réexécute dans le même mode avec le nom du script comme premier argument de ligne de commande. Dans son mode conforme POSIX, il s'exécute bien sûr lui-même dans son mode conforme POSIX, obéissant ainsi à l'exigence POSIX d'invoquer un shell conforme POSIX.
  • Le shell Z, le shell Almquist et le shell Korn s'exécutent /bin/shavec le nom du script inséré avant les autres arguments comme premier argument de ligne de commande. Le shell Z, le shell Almquist et le shell Korn (tentent) d'invoquer un shell conforme POSIX à force de supposer que le /bin/shprogramme en est un.
ilkkachu
la source
Pourriez-vous s'il vous plaît partager le code source de ce programme C ..
GypsyCosmonaut
int main(int argc, char *argv[]){printf("I am %s\n",argv[0]);}
Stig Hemmer
C'est à peu près ça.
ilkkachu
4

Le shell exécuté est soit celui appelé dans la ligne de commande, soit celui dans le shebang (si la ligne de commande ne le spécifie pas).

Ainsi, les versions 1 et 4 fonctionneront avec sh, 2 et 5 avec bash et 6 peuvent ne pas fonctionner si vous utilisez sh (et quelques autres) de manière interactive. Bash démarre le script. Ksh aussi. Zsh démarre comme sh.

Seuls ceux démarrés comme shutiliseront l'option posix si bash est lié à /bin/sh.

Ajoutez cette ligne à votre script pour détecter si une version bash ksh ou zsh l'exécute:

echo "Hello World $BASH_VERSION $KSH_VERSION $ZSH_VERSION"
Isaac
la source