242 votes

But de #!/usr/bin/python3 shebang

J'ai remarqué cela dans quelques langages de script, mais dans cet exemple, j'utilise python. Dans de nombreux tutoriels, on commence par #!/usr/bin/python3 sur la première ligne. Je ne comprends pas pourquoi nous avons cela.

  • Le système d'exploitation ne devrait-il pas savoir qu'il s'agit d'un script python (manifestement, il est installé puisque vous y faites référence) ?
  • Que faire si l'utilisateur utilise un système d'exploitation qui n'est pas basé sur Unix ?
  • La langue est installée dans un dossier différent pour une raison quelconque.
  • L'utilisateur a une version différente. Surtout quand il ne s'agit pas d'un numéro de version complet (comme Python3 vs Python32).

Au contraire, je pourrais voir que cela casse le script de python pour les raisons énumérées ci-dessus.

3voto

awiebe Points 995

En fait, la détermination du type de fichier est très compliquée, de sorte que le système d'exploitation ne peut pas simplement le savoir. Il peut faire beaucoup de suppositions basées sur -

  • extension
  • UTI
  • MIME

Mais la ligne de commande ne s'embarrasse pas de tout cela, parce qu'elle fonctionne sur une couche rétrocompatible limitée, datant de l'époque où ces fantaisies ne signifiaient rien. Si vous double-cliquez dessus, bien sûr, un système d'exploitation moderne peut s'en rendre compte, mais si vous l'exécutez à partir d'un terminal, alors non, parce que le terminal ne se soucie pas des API de saisie de fichiers spécifiques à votre système d'exploitation.

En ce qui concerne les autres points. C'est une commodité, il est également possible d'exécuter

python3 path/to/your/script

Si votre python n'est pas dans le chemin spécifié, alors cela ne fonctionnera pas, mais nous avons tendance à installer des choses pour que des choses comme celles-ci fonctionnent, et non l'inverse. Cela n'a pas d'importance si vous êtes sous *nix, c'est à votre shell de prendre en compte ou non cette ligne car c'est un fichier shellcode . Ainsi, par exemple, vous pouvez exécuter bash sous Windows.

Vous pouvez en fait omettre complètement cette ligne, cela signifie simplement que l'appelant devra spécifier un interprète. Ne mettez pas non plus vos interprètes dans des emplacements non standard et essayez ensuite d'appeler scripts sans fournir un interprète.

2voto

Ciro Santilli Points 3341

Le site exec du noyau Linux comprend les shebangs ( #! ) nativement

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/python3 et le fichier courant comme premier argument :

/usr/bin/python3 /path/to/script.py

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

Et par analogie, si vous décidez d'utiliser env à la place, ce que vous devriez probablement toujours faire pour travailler sur des systèmes qui ont le format python3 dans un autre endroit, notamment pyenv voir aussi cette question tout le tralala :

#!/usr/bin/env python3

finit par appeler de manière analogue :

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

qui fait ce que vous attendez de env python3 : recherches PATH para python3 et fonctionne /usr/bin/python3 /path/to/script.py .

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 la présence d'octets 7f 45 4c 46 (qui se trouve également être lisible par l'homme pour le .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 : Comment un noyau fait-il fonctionner un fichier binaire exécutable sous linux ?

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 précise cependant les shebangs : 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". macOS et FreeBSD semblent également l'implémenter.

PATH motivation de recherche

Il est probable que l'une des principales raisons de l'existence des shebangs est le fait que sous Linux, nous voulons souvent exécuter des commandes à partir de PATH tout comme :

basename-of-command

au lieu de :

/full/path/to/basename-of-command

Mais alors, sans le mécanisme shebang, comment Linux saurait-il comment lancer chaque type de fichier ?

Codage en dur de l'extension dans les commandes :

 basename-of-command.py

ou d'implémenter la recherche PATH sur chaque interpréteur :

python3 basename-of-command

serait une possibilité, mais cela présente le problème majeur que tout se casse la figure si nous décidons un jour de refactoriser la commande dans un autre langage.

Les shebangs résolvent ce problème à merveille.

Voir aussi : Pourquoi les gens écrivent-ils #!/usr/bin/env python sur la première ligne d'un script Python ?

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X