71 votes

Est-ce que #!/bin/sh est lu par l'interpréteur ?

En bash o sh Je pense que tout ce qui commence par # est un commentaire .

Mais en bash scripts que nous écrivons :

#!/bin/bash

Et dans Python scripts, il y en a :

#!/bin/python

Est-ce que cela signifie que # par lui-même est un commentaire alors que #! ne l'est pas ?

106voto

Eliah Kagan Points 111731

El #! la ligne est utilisée antes de le script est exécuté, puis ignoré quand le script s'exécute.

Vous demandez quelle est la différence entre un ligne shebang et un commentaire ordinaire.

Une ligne commençant par #! est tout autant un commentaire que n'importe quelle autre ligne qui commence par # . Ceci est vrai si le #! est la première ligne du fichier, ou n'importe où ailleurs. #!/bin/sh a un effet mais il n'est pas lu par l'interprète lui-même .

# n'est pas un commentaire dans tous les langages de programmation mais, comme vous le savez, c'est un commentaire dans les shells de type Bourne, notamment sh y bash (ainsi que la plupart des shells de style non-Bourne, tels que csh ). C'est également un commentaire en Python . Et c'est un commentaire dans une variété de fichiers de configuration qui ne sont pas vraiment scripts du tout (comme /etc/fstab ).

Supposons qu'un Shell Shell commence par #!/bin/sh . Il s'agit d'un commentaire, et l'interpréteur (le Shell) ignore tout ce qui se trouve sur la ligne qui suit l'élément # caractère.

L'objectif d'un #! n'est pas de donner des informations à l'interprète. Le but de la #! est d'indiquer au système d'exploitation (ou au processus qui lance l'interpréteur) ce qu'il faut utiliser comme interprète .

  • Si vous invoquez le script comme un fichier exécutable, par exemple, en exécutant ./script.sh le système consulte la première ligne pour voir si elle commence par #! suivi de zéro ou plusieurs espaces, suivi d'une commande. S'il le fait, il exécute cette commande avec le nom du script comme argument. Dans cet exemple, il exécute /bin/sh script.sh (ou, techniquement, /bin/sh ./script.sh ).

  • Si vous invoquez le script en appelant explicitement l'interpréteur, la fonction #! La ligne n'est jamais consultée. Ainsi, si vous exécutez sh script.sh la première ligne n'a aucun effet. Si script2.sh La première ligne de l'article est #!/usr/games/nibbles en cours d'exécution sh script2.sh n'essaiera pas d'ouvrir le script en nibbles (mais ./script2.sh volonté).

Vous remarquerez que dans les deux cas, l'extension du script ( .sh ), s'il en a un, a un impact sur la façon dont il est géré. Dans un système de type Unix, cela n'affecte généralement pas la façon dont le script est exécuté. Sur certains autres systèmes, comme Windows, l'option #! La ligne shebang pourrait être entièrement ignorée par le système, et l'extension pourrait déterminer ce qui exécute les scripts. (Cela ne signifie pas que vous devez donner à vos scripts des extensions, mais c'est une des raisons pour lesquelles, si vous le faites, elles devraient être correctes).

#! a été choisi pour servir précisément cet objectif parce que # commence un commentaire. Le site #! est pour le système, pas pour l'interprète, et elle doit être ignorée par l'interprète.

Ligne Shebang pour les scripts de Bash

Vous avez dit (à l'origine) que vous utilisez #!/bin/sh para bash scripts. Vous ne devriez le faire que si le scripts ne requiert aucun des éléments suivants bash Les extensions sh doit être capable d'exécuter le script. sh n'est pas toujours un lien symbolique vers bash . Souvent, y compris sur tous les systèmes Debian et Ubuntu récents à distance , sh est un lien symbolique vers dash .

Ligne Shebang pour Python scripts

Vous avez aussi dit (dans la première version de votre question, avant modification) que vous démarrez vos scripts Python avec #!/bin/sh read by the interpretor . Si vous voulez dire cela littéralement, alors vous devriez définitivement arrêter de le faire. Si hello.py commence par cette ligne, en exécutant ./hello.py s'exécute :

/bin/sh read by the interpretor hello.py

/bin/sh va essayer d'exécuter un script appelé read (avec by the interpretor hello.py comme ses arguments), read ne sera (espérons-le) pas trouvé, et votre script Python ne sera jamais vu par un interprète Python.

Si vous faites cette erreur mais n'avez pas le problème que je décris, vous invoquez probablement vos scripts Python en spécifiant explicitement l'interpréteur (par exemple, python hello.py ), ce qui fait que la première ligne est ignorée. Lorsque vous distribuez vos scripts à d'autres, ou que vous les utilisez longtemps après, il peut ne pas être clair que cela est nécessaire pour qu'ils fonctionnent. Il est préférable de les corriger maintenant. Ou au moins enlever la première ligne entièrement, de sorte que lorsqu'ils échouent à s'exécuter avec la commande ./ le message d'erreur aura un sens.

Pour les scripts de Python, si vous savez où se trouve (ou va se trouver) l'interpréteur Python, vous pouvez écrire la commande #! de la même manière :

#!/usr/bin/python

Ou, s'il s'agit d'un script de Python 3, vous devez spécifier python3 puisque python est presque toujours Python 2 :

#!/usr/bin/python3

Cependant, le problème est que pendant que /bin/sh est censé exister toujours, et /bin/bash existe presque toujours sur les systèmes où bash est livré avec le système d'exploitation, Python peut exister à différents endroits.

C'est pourquoi de nombreux programmeurs Python l'utilisent à la place :

#!/usr/bin/env python

(Ou #!/usr/bin/env python3 pour Python 3).

Cela fait que le script dépend de env être au "bon endroit" au lieu de s'appuyer sur python être au bon endroit. C'est une bonne chose, parce que :

  • env est presque toujours situé dans /usr/bin .
  • Sur la plupart des systèmes, l'un ou l'autre python debe exécuter votre script est celui qui apparaît en premier dans la fenêtre PATH . Démarrage hello.py con #!/usr/bin/env python faire ./hello.py exécuter /usr/bin/env python hello.py ce qui équivaut (virtuellement) à exécuter python hello.py .

La raison pour laquelle vous ne pouvez pas utiliser #!python c'est que :

  • Vous voulez que l'interprète spécifié soit donné par un chemin absolu (c'est-à-dire, commençant par / ).
  • Le processus appelant exécuterait python dans le répertoire actuel . Rechercher le chemin lorsque la commande ne contient pas de slash est un comportement spécifique Shell.

De temps en temps, un Python ou autre script qui n'est pas un script script aura une ligne shebang commençant par #!/bin/sh ... donde ... est un autre code. C'est parfois correct, car il existe certaines façons d'invoquer le Shell compatible avec Bourne ( sh ) avec des arguments pour qu'il invoque un interpréteur Python. (L'un des arguments contiendra probablement python .) Cependant, dans la plupart des cas, #!/usr/bin/env python est plus simple, plus élégant et plus susceptible de fonctionner comme vous le souhaitez.

Shebang Lines dans d'autres langues

De nombreux langages de programmation et de script, et certains autres formats de fichiers, utilisent # comme un commentaire. Pour chacun d'entre eux, un fichier dans le langage peut être exécuté par un programme qui le prend comme argument en spécifiant le programme sur la première ligne après #! .

Dans certains langages de programmation, # n'est pas normalement un commentaire, mais dans un cas spécial, la première ligne est ignorée si elle commence par #! . Cela facilite l'utilisation de #! syntaxe même si # ne fait pas autrement d'une ligne un commentaire.

Lignes Shebang pour les fichiers qui ne sont pas exécutés en tant que scripts.

Bien que cela soit moins intuitif, tout fichier dont le format peut accueillir une première ligne commençant par #! suivi du chemin complet d'un exécutable peut avoir une ligne shebang. Si vous faites cela, et que le fichier est marqué comme exécutable, vous pouvez alors l'exécuter comme un programme... et l'ouvrir comme un document.

Certaines applications utilisent ce comportement intentionnellement. Par exemple, dans VMware, .vmx définissent les machines virtuelles. Vous pouvez "exécuter" une machine virtuelle comme s'il s'agissait d'un script parce que ces fichiers sont marqués comme exécutables et possèdent une ligne shebang qui permet de les ouvrir dans un utilitaire VMware.

Lignes Shebang pour les fichiers qui ne s'exécutent pas comme des Scrips mais qui agissent comme des scripts de toute façon

rm supprime les fichiers. Il ne s'agit pas d'un langage de script. Cependant, un fichier qui démarre #!/bin/rm et est marqué exécutable peut être exécuté, et quand vous l'exécutez, rm est invoqué sur elle, la supprimant.

Ceci est souvent conceptualisé comme "le fichier se supprime lui-même". Mais le fichier ne s'exécute pas vraiment. Cela ressemble plus à la situation décrite ci-dessus pour .vmx des fichiers.

Pourtant, parce que le #! facilite l'exécution d'une commande simple (y compris les arguments de la ligne de commande), vous pouvez effectuer quelques scripts de cette manière. Comme exemple simple d'un "script" plus sophistiqué que #!/bin/rm considère :

#!/usr/bin/env tee -a

Ceci prend l'entrée de l'utilisateur de manière interactive, le renvoie à l'utilisateur ligne par ligne, et l'ajoute à la fin du fichier "script".

Utile ? Pas très. Conceptuellement intéressant ? Totalement ! Oui. (Un peu.)

Concepts de programmation/scénario similaires (juste pour le plaisir)

7voto

Goran Miskovic Points 530

Un shebang est la séquence de caractères constituée des caractères signe numérique et point d'exclamation (par exemple "# !") lorsqu'elle apparaît comme les deux caractères initiaux de la ligne initiale d'un script.

Sous les systèmes d'exploitation *nix, lorsqu'un script commençant par un shebang est exécuté, le chargeur de programme analyse le reste de la ligne initiale du script comme une directive d'interprétation ; le programme d'interprétation spécifié est exécuté à la place, en lui passant comme argument le chemin qui a été initialement utilisé lors de la tentative d'exécution du script. Par exemple, si un script est nommé avec le chemin "path/to/your-script", et qu'il commence par la ligne suivante :

#!/bin/sh

alors le chargeur de programme est chargé d'exécuter le programme "/bin/sh" à la place, par exemple le Bourne Shell ou un Shell compatible, en passant "path/to/your-Shell" comme premier argument.

En conséquence, un script est nommé avec le chemin "path/to/Python-script" et il commence par la ligne suivante :

#!/bin/python

alors le programme chargé reçoit l'instruction d'exécuter le programme "/bin/Python" à la place, par exemple l'interpréteur Python, en passant "path/to/Python-script" comme premier argument.

En bref, "#" commente une ligne, tandis que la séquence de caractères "# !" qui apparaît comme les deux premiers caractères de la ligne initiale d'un script a une signification décrite comme ci-dessus.

Pour plus de détails, voir Pourquoi certains scripts commencent-ils par # ! ... ?

Source : Certaines sections de cette réponse sont tirées (avec une légère modification) de Shebang (Unix) en Wikipédia en anglais (par Contributeurs de Wikipédia ). Cet article est sous licence CC-BY-SA 3.0 comme le contenu utilisateur ici sur AU, donc cette dérivation est autorisée avec attribution.

5voto

saji89 Points 11609

#! est appelé le shebang lorsqu'il apparaît comme les deux premiers caractères de la ligne initiale d'un script. Il est utilisé dans les script pour indiquer un interprète pour l'exécution. Le site shebang est pour le système d'exploitation (kernel), pas pour le Shell ; il ne sera donc pas interprété comme un commentaire.

Courtoisie : http://en.wikipedia.org/wiki/Shebang_%28Unix%29

En général, si un fichier est exécutable, mais n'est en réalité pas un exécutable (binaire), et qu'une telle ligne est présente, le programme spécifié après # ! après # ! est lancé avec le nom de script et tous ses arguments. Ces deux caractères # et ! doivent être les deux premiers octets du fichier !

Informations détaillées : http://wiki.bash-hackers.org/scripting/basics#the_shebang

0voto

Non, il est uniquement utilisé par le exec appel système du noyau Linux, et traité comme un commentaire par l'interpréteur

Quand vous faites sur bash :

./something

sous Linux, cela appelle le exec appel système 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, alors le reste de la ligne est analysé par le noyau Linux, qui fait un autre exec appel avec 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 des octets différents, alors l'option 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 se trouve également être lisible par l'homme pour .ELF ). Confirmons cela en lisant les 4 premiers octets de /bin/ls qui est un exécutable ELF :

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

sortie :

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 lance 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 à l'aide de l'option 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 QEMU .

Je ne pense pas que POSIX spécifie les shebangs cependant : https://unix.stackexchange.com/a/346214/32558 Bien qu'il en soit fait mention dans des sections de justification, et sous la forme "si les scripts exécutables sont supportés par le système, quelque chose peut se produire".

SistemesEz.com

SystemesEZ est une communauté de sysadmins où vous pouvez résoudre vos problèmes et vos doutes. Vous pouvez consulter les questions des autres sysadmins, poser vos propres questions ou résoudre celles des autres.

Powered by:

X