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

61

Dans bash ou sh , tout élément commençant par # est un commentaire .

Mais dans les scripts bash , nous écrivons:

#!/bin/bash

Et dans les scripts Python, il y a:

#!/bin/python

Cela signifie-t-il que # en soi est un commentaire alors que #! ne l'est pas?

    
posée Gaurav Sharma 09.01.2013 - 07:04
la source

4 réponses

91

La ligne #! est utilisée avant le script est exécuté, puis ignoré lorsque le script s'exécute.

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

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

# n'est pas un commentaire dans tous les langages de programmation mais, comme vous le savez, il s'agit d'un commentaire de type Bourne incluant sh et bash (ainsi que la plupart des shells de style non-Bourne, comme%) code%). Il est également un commentaire en Python . Et c'est un commentaire dans une variété de fichiers de configuration qui ne sont pas vraiment des scripts (comme csh ).

Supposons qu'un script shell commence par /etc/fstab . C'est un commentaire, et l'interpréteur (le shell) ignore tout sur la ligne après le caractère #!/bin/sh .

L'objet d'une ligne # n'est pas de donner des informations à l'interpréteur. Le but de la ligne #! est d'indiquer au système d'exploitation (ou à tout processus qui lance l'interpréteur) quoi utiliser comme interpréteur .

  • Si vous appelez le script en tant que fichier exécutable, par exemple, en exécutant #! , le système consulte la première ligne pour voir si commence par ./script.sh , suivi de zéro espace ou plus, suivi d'un commander. Si c'est le cas, il exécute cette commande avec le nom du script comme argument. Dans cet exemple, il exécute #! (ou, techniquement, /bin/sh script.sh ).

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

Vous remarquerez que l’extension du script ( ./script2.sh ), si elle en a un, n’a aucun impact sur son exécution. Dans un système de type Unix, cela n'affecte généralement pas l'exécution du script. Sur certains autres systèmes, comme Windows, la ligne .sh shebang peut être entièrement ignorée par le système et l'extension peut déterminer ce qui exécute les scripts. (Cela ne signifie pas que vous devez donner vos extensions de scripts, mais c'est l'une des raisons pour lesquelles, si vous le faites, elles devraient être correctes.)

#! a été choisi pour atteindre cet objectif précisément car #! commence un commentaire. La ligne # est destinée au système et non à l'interpréteur et doit être ignorée par l'interpréteur.

Ligne Shebang pour les scripts Bash

Vous (à l'origine) avez dit que vous utilisez #! pour les scripts #!/bin/sh . Vous ne devriez le faire que si le script ne nécessite aucune des extensions bash - bash doit pouvoir exécuter le script. sh n'est pas toujours un lien symbolique vers sh . Souvent, y compris sur tous les systèmes Debian et Ubuntu récents à distance, bash est un lien symbolique vers sh .

Ligne Shebang pour les scripts Python

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

/bin/sh read by the interpretor hello.py

./hello.py essaiera d'exécuter un script appelé /bin/sh (avec read comme arguments), by the interpretor hello.py sera (espérons-le) introuvable, et votre script Python ne sera jamais vu par un interpréteur Python.

Si vous faites cette erreur sans avoir le problème que je décris, vous appelez probablement vos scripts Python en spécifiant explicitement l’interpréteur (par exemple, read ), en ignorant la première ligne. Lorsque vous distribuez vos scripts à d’autres utilisateurs ou que vous les utilisez longtemps plus tard, il n’est peut-être pas évident que cela soit nécessaire pour qu’ils fonctionnent. Il vaut mieux les réparer maintenant. Ou du moins supprimer complètement la première ligne, de sorte que, si elles ne parviennent pas à s'exécuter avec python hello.py , le message d'erreur aura un sens.

Pour les scripts Python, si vous savez où l’interpréteur Python est (ou va être), vous pouvez écrire la ligne ./ de la même manière:

#!/usr/bin/python

Ou, si c'est un script Python 3, vous devez spécifier #! , puisque python3 est presque toujours Python 2 :

#!/usr/bin/python3

Cependant, le problème est que, bien que python soit supposé exister toujours, et que /bin/sh existe presque toujours sur les systèmes où /bin/bash est fourni avec le système d'exploitation, Python peut exister à divers endroits.

Par conséquent, de nombreux programmeurs Python l'utilisent à la place:

#!/usr/bin/env python

(ou bash pour Python 3.)

Cela fait que le script utilise #!/usr/bin/env python3 comme étant au "bon endroit" au lieu de compter sur env au bon endroit. C'est une bonne chose parce que:

  • python est presque toujours situé dans env .
  • Sur la plupart des systèmes, quel que soit /usr/bin devrait exécuter votre script est celui qui apparaît en premier dans python . À partir de PATH avec hello.py make #!/usr/bin/env python exécutez ./hello.py , ce qui équivaut (virtuellement) à l'exécution de /usr/bin/env python hello.py .

La raison pour laquelle vous ne pouvez pas utiliser python hello.py est que:

  • Vous voulez que l’interpréteur spécifié soit donné par un chemin absolu (c’est-à-dire commençant par #!python ).
  • Le processus appelant exécutera / dans le répertoire en cours. Le comportement de recherche dans le chemin lorsque la commande ne contient pas de barre oblique est un comportement de shell spécifique.

Parfois, un script Python ou autre qui n’est pas un script shell aura une ligne shebang commençant par python#!/bin/sh ... est un autre code. Ceci est parfois correct, car il existe des moyens d’appeler le shell compatible Bourne ( ... ) avec des arguments lui permettant d’appeler un interpréteur Python. (L'un des arguments contiendra probablement sh .) Cependant, dans la plupart des cas, python est plus simple, plus élégant et plus susceptible de fonctionner comme vous le souhaitez.

Lignes de shebang dans d’autres langues

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

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

Lignes de shebang pour les fichiers qui ne s'exécutent pas en tant que scripts

Bien que ce soit moins intuitif, tout fichier dont le format de fichier peut contenir 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 l'exécuter comme un programme ... en l'ouvrant comme un document.

Certaines applications utilisent ce comportement intentionnellement. Par exemple, dans VMware, les fichiers #! définissent des machines virtuelles. Vous pouvez "exécuter" une machine virtuelle comme s'il s'agissait d'un script car ces fichiers sont marqués comme étant exécutables et ont une ligne shebang leur permettant d'être ouverts dans un utilitaire VMware.

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

.vmx supprime les fichiers. Ce n'est pas un langage de script. Toutefois, un fichier qui démarre rm et qui est marqué comme exécutable peut être exécuté et, lorsque vous l'exécutez, #!/bin/rm y est appelé en le supprimant.

Ceci est souvent conceptualisé comme "le fichier se supprime". Mais le fichier ne fonctionne pas vraiment du tout. Cela ressemble plus à la situation décrite ci-dessus pour les fichiers rm .

Cependant, comme la ligne .vmx facilite l'exécution d'une commande simpliste (y compris les arguments de ligne de commande), vous pouvez effectuer certains scripts de cette manière. Comme exemple simple de "script" plus sophistiqué que #! , considérez:

#!/usr/bin/env tee -a

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

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

Concepts conceptuels et de programmation similaires sur le plan conceptuel (juste pour le plaisir)

réponse donnée Eliah Kagan 09.01.2013 - 08:30
la source
7

Un shebang est la séquence de caractères composée du signe du nombre de caractères et du point d’exclamation (par exemple, "#!") lorsqu'il se présente sous la forme des deux premiers caractères 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 en tant que directive d'interpréteur; le programme d'interpréteur spécifié est exécuté à la place, en lui transmettant comme argument le chemin utilisé initialement 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 shell Bourne ou un shell compatible, en passant "path / to / your-script" 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é est chargé d'exécuter le programme "/ bin / python" à la place, par exemple Interprète Python, en passant "path / to / python-script" comme premier argument.

En bref "#" commentera une ligne pendant que la séquence de caractères "#!" Les deux premiers caractères de la ligne initiale d’un script ont la signification indiquée ci-dessus.

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

Source: Certaines sections de cette réponse sont dérivées (avec une légère modification) de Shebang (Unix) sur Wikipedia anglais (par les contributeurs Wikipedia ). Cet article est sous licence CC-BY-SA 3.0 , identique au contenu utilisateur ici sur AU, cette dérivation est donc autorisée avec attribution.

    
réponse donnée Goran Miskovic 09.01.2013 - 07:57
la source
4

#! est appelé shebang lorsqu'il se présente sous la forme des deux premiers caractères de la ligne initiale d'un script. Il est utilisé dans les scripts pour indiquer un interpréteur à exécuter. Le shebang est pour le système d'exploitation (noyau), pas pour le shell; il ne sera donc pas interprété comme un commentaire.

Courtoisie: lien

  

En général, si un fichier est exécutable, mais en réalité pas un exécutable   (binaire) programme, et une telle ligne est présente, le programme spécifié   après #! est démarré avec le scriptname et tous ses arguments. Celles-ci   deux personnages # et! doivent être les deux premiers octets du fichier!

Informations détaillées: lien

    
réponse donnée saji89 09.01.2013 - 07:34
la source
0

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

Quand vous faites sur 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 transmis à exec : lien

  

if ((bprm- & gt; buf [0]! = '#') || (bprm- & gt; buf [1]! = '!'))

Ceci lit les tous premiers octets du fichier et les compare à #! .

Si cela est vrai, le reste de la ligne est analysé par le noyau Linux, ce qui rend un autre appel exec avec le chemin d'accès /usr/bin/env python et le fichier actuel comme premier argument:

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

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

Et oui, vous pouvez faire une boucle infinie avec:

#!/a

et un fichier exécutable à /a

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

Si le fichier a démarré avec des octets différents, l'appel système exec utiliserait un gestionnaire différent. L'autre gestionnaire intégré le plus important concerne les fichiers exécutables ELF: lien qui vérifie les octets 7f 45 4c 46 (ce qui se trouve être lisible pour .ELF ). Ceci lit le fichier ELF, le met en mémoire correctement et lance un nouveau processus avec lui. Voir aussi: lien

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

Je ne pense pas que POSIX spécifie des shebangs cependant: lien , bien qu'il mentionne dans les sections de justification, et sous la forme "si les scripts exécutables sont supportés par le système, quelque chose peut arriver".

    
la source

Lire d'autres questions sur les étiquettes