web-dev-qa-db-fra.com

Le Shebang détermine-t-il le Shell qui exécute le script?

C'est peut-être une question stupide, mais je la pose toujours. Si j'ai déclaré un Shebang

#!/bin/bash 

au début de my_Shell_script.sh, je dois donc toujours invoquer ce script en utilisant bash

[my@comp]$bash my_Shell_script.sh

ou puis-je utiliser par exemple.

[my@comp]$sh my_Shell_script.sh

et mon script détermine le Shell en cours d'exécution en utilisant le shebang? Est-ce la même chose avec ksh shell? J'utilise AIX.

90
jrara

Shebang#! Est une instance lisible par l'homme d'un nombre magique composé de la chaîne d'octets 0x23 0x21, Qui est utilisée par le exec() famille de fonctions pour déterminer si le fichier à exécuter est un script ou un binaire. Lorsque le Shebang est présent, exec() exécutera à la place l'exécutable spécifié après le Shebang.

Notez que cela signifie que si vous appelez un script en spécifiant l'interpréteur sur la ligne de commande, comme cela se fait dans les deux cas donnés dans la question, exec() exécutera l'interpréteur spécifié sur la ligne de commande, il ne regardera même pas le script.

Ainsi, comme d'autres l'ont remarqué, si vous voulez que exec() appelle l'interpréteur spécifié sur la ligne Shebang, le script doit avoir le bit exécutable défini et appelé comme ./my_Shell_script.sh.

Le comportement est facile à démontrer avec le script suivant:

#!/bin/ksh
readlink /proc/$$/exe

Explication:

  • #!/bin/ksh Définit ksh comme interprète.

  • $$ Contient le PID du processus en cours.

  • /proc/pid/exe Est un lien symbolique vers l'exécutable du processus (au moins sous Linux; sous AIX, /proc/$$/object/a.out est un lien vers l'exécutable).

  • readlink affichera la valeur du lien symbolique.

Exemple:

Remarque : Je le démontre sur Ubuntu, où le shell par défaut /bin/sh Est un lien symbolique vers tiret ie /bin/dash et /bin/ksh est un lien symbolique vers /etc/alternatives/ksh, qui à son tour est un lien symbolique vers /bin/pdksh.

$ chmod +x getshell.sh
$ ./getshell.sh 
/bin/pdksh
$ bash getshell.sh 
/bin/bash
$ sh getshell.sh 
/bin/dash
123
Thomas Nyman

Oui. Soit dit en passant, ce n'est pas une question stupide. Une référence pour ma réponse est ici . Démarrage d'un script avec #!

  • Cela s'appelle un Shebang ou une ligne de "bang".

  • Ce n'est rien d'autre que le chemin absolu vers l'interpréteur Bash.

  • Il se compose d'un signe numérique et d'un caractère de point d'exclamation (#!), Suivi du chemin complet vers l'interpréteur tel que/bin/bash.

    Tous les scripts sous Linux s'exécutent à l'aide de l'interpréteur spécifié sur une première ligne Presque tous les scripts bash commencent souvent par #!/Bin/bash (en supposant que Bash a été installé dans/bin) Cela garantit que Bash sera utilisé pour interpréter le script, même s'il est exécuté sous un autre Shell. Le Shebang a été introduit par Dennis Ritchie entre la version 7 Unix et la version 8 aux laboratoires Bell. Il a ensuite été ajouté à la ligne BSD de Berkeley.

Ignorer une ligne d'interprète (Shebang)

Si vous ne spécifiez pas de ligne d'interpréteur, la valeur par défaut est généralement/bin/sh. Mais, il est recommandé de définir la ligne #!/Bin/bash.

9
vfbsilva

L'appel système exec du noyau Linux comprend les shebangs (#!) nativement

Quand tu fais bash:

./something

sous Linux, cela appelle l'appel système exec avec le chemin ./something.

Cette ligne du noyau est appelée sur le fichier passé à exec: https://github.com/torvalds/linux/blob/v4.8/fs/binfmt_script.c#L25 =

if ((bprm->buf[0] != '#') || (bprm->buf[1] != '!'))

Il lit les tout premiers octets du fichier et les compare à #!.

Si la comparaison est vraie, le reste de la ligne est analysé par le noyau Linux, qui effectue un autre appel exec avec le chemin /usr/bin/env python et le fichier courant comme premier argument:

/usr/bin/env python /path/to/script.py

et cela fonctionne pour tout langage de script qui utilise # comme caractère de commentaire.

Et oui, vous pouvez faire une boucle infinie avec:

printf '#!/a\n' | Sudo tee /a
Sudo chmod +x /a
/a

Bash reconnaît l'erreur:

-bash: /a: /a: bad interpreter: Too many levels of symbolic links

#! se trouve être lisible par l'homme, mais ce n'est pas obligatoire.

Si le fichier a commencé avec différents octets, l'appel système exec utiliserait un gestionnaire différent. L'autre gestionnaire intégré le plus important concerne les fichiers exécutables ELF: https://github.com/torvalds/linux/blob/v4.8/fs/binfmt_elf.c#L1305 qui vérifie les octets 7f 45 4c 46 (qui est également lisible par l'homme pour .ELF). Confirmons qu'en lisant les 4 premiers octets de /bin/ls, qui est un exécutable ELF:

head -c 4 "$(which ls)" | hd 

production:

00000000  7f 45 4c 46                                       |.ELF|
00000004                                                                 

Ainsi, lorsque le noyau voit ces octets, il prend le fichier ELF, le place correctement en mémoire et démarre un nouveau processus avec lui. Voir aussi: https://stackoverflow.com/questions/8352535/how-does-kernel-get-an-executable-binary-file-running-under-linux/31394861#31394861

Enfin, vous pouvez ajouter vos propres gestionnaires Shebang avec le binfmt_misc mécanisme. Par exemple, vous pouvez ajouter un gestionnaire personnalisé pour .jar fichiers . Ce mécanisme prend même en charge les gestionnaires par extension de fichier. Une autre application consiste à exécuter de manière transparente des exécutables d'une architecture différente avec QEM .

Je ne pense pas que POSIX spécifie les shebangs, cependant: https://unix.stackexchange.com/a/346214/32558 , bien qu'il le mentionne dans les sections de justification et sous la forme "si exécutable" les scripts sont supportés par le système quelque chose peut arriver ".

En fait, si vous le prenez en conséquence, l'exécutable noté dans la ligne Shebang n'est qu'un exécutable. Il est logique d'utiliser un interpréteur de texte comme exécutable, mais ce n'est pas nécessaire. Juste pour clarification et démonstration, j'ai fait un test plutôt inutile:

#!/bin/cat
useless text
more useless text
still more useless text

Nommé le fichier test.txt et définissez le bit exécutable chmod u+x test.txt, puis "l'a appelé": ./test.txt. Comme prévu, le contenu du fichier est sorti. Dans ce cas, le chat n'ignore pas la ligne Shebang. Il sort simplement toutes les lignes. Tout interprète utile devrait donc pouvoir ignorer cette ligne Shebang. Pour bash, Perl et PHP, il s'agit simplement d'une ligne de commentaire. Alors oui, ceux-ci ignorent la ligne Shebang.

4
Siegfried