Est-ce que les interprètes en chaîne via des lignes de shebang sont portables?

Lier un script à un interpréteur spécifique via une ligne appelée shebang est une pratique bien connue sur les systèmes d’exploitation POSIX . Par exemple, si le script suivant est exécuté (avec des permissions de système de fichiers suffisantes), le système d’exploitation lancera l’interpréteur /bin/sh avec le nom de fichier du script comme premier argument. Par la suite, le shell exécutera les commandes dans le script en ignorant la ligne shebang qu’il traitera comme un commentaire.

 #! /bin/sh date -R echo hello world 

Sortie possible:

 Sat, 01 Apr 2017 12:34:56 +0100 hello world 

J’avais l’ habitude de croire que l’interpréteur ( /bin/sh dans cet exemple) doit être un exécutable natif et ne peut pas être un script lui-même qui, à son tour, nécessiterait un autre interpréteur pour être lancé.

Cependant, je suis allé de l’avant et j’ai néanmoins essayé l’expérience suivante.

En utilisant le shell muet suivant enregistré sous /tmp/interpreter.py , …

 #! /usr/bin/python3 import sys import subprocess for script in sys.argv[1:]: with open(script) as istr: status = any( map( subprocess.call, map( str.split, filter( lambda s : s and not s.startswith('#'), map(str.ssortingp, istr) ) ) ) ) if status: sys.exit(status) 

… et le script suivant enregistré sous /tmp/script.xyz ,

 #! /tmp/interpreter.py date -R echo hello world 

… J’ai pu (après avoir fait les deux fichiers exécutables), exécuter script.xyz .

 5gon12eder: / tmp> ls -l
 total 8
 -rwxr-x --- 1 5gon12eder 5gon12eder 493 juin 19 01:01 interpreter.py
 -rwxr-x --- 1 5gon12eder 5gon12eder 70 juin 19 01:02 script.xyz
 5gon12eder: / tmp> ./script.xyz
 Lun. 19 juin 2017 01:07:19 +0200
 Bonjour le monde

Cela m’a surpris. J’ai même pu lancer scrip.xyz via un autre script.

Donc, ce que je demande, c’est ceci:

  • Le comportement observé par mon expérience est-il portable?
  • L’expérience a-t-elle même été menée correctement ou existe-t-il des situations où cela ne fonctionne pas? Qu’en est-il des différents systèmes d’exploitation (de type Unix)?
  • Si cela est supposé fonctionner, est-il vrai qu’il n’y a pas de différence observable entre un exécutable natif et un script interprété en ce qui concerne l’invocation?

  1. Voir le texte en gras ci-dessous:

    Ce mécanisme permet aux scripts d’être utilisés dans pratiquement tous les contextes des programmes compilés normaux, y compris en tant que programmes système complets et même en tant qu’interprètes d’autres scripts . Cependant, certaines versions antérieures du support du kernel limitaient la longueur de la directive interpréteur à environ 32 caractères (16 seulement lors de la première implémentation), ne divisaient pas le nom de l’interprète en parameters ou comportaient d’autres particularités. . De plus, certains systèmes modernes permettent de restreindre ou de désactiver l’ensemble du mécanisme à des fins de sécurité (par exemple, la prise en charge de set-user-id a été désactivée pour les scripts sur de nombreux systèmes). – WP

  2. Et cette sortie de COLUMNS=75 man execve | grep -nA 23 " Interpreter scripts" | head -39 COLUMNS=75 man execve | grep -nA 23 " Interpreter scripts" | head -39 COLUMNS=75 man execve | grep -nA 23 " Interpreter scripts" | head -39 sur une boîte Ubuntu 17.04 , en particulier les lignes # 186- # 189 qui nous indique ce qui fonctionne sous Linux (les scripts peuvent être des interprètes, jusqu’à quatre niveaux de profondeur):

 166: Scripts d'interprète
 167- Un script d'interpréteur est un fichier texte avec une autorisation d'exécution
 168- activé et dont la première ligne est de la forme:
 169-
 170- #!  interprète [option-arg]
 171-
 172- L'interpréteur doit être un chemin d'access valide pour un fichier exécutable.
 173- Si l'argument filename de execve () spécifie un interpréteur
 174-script, puis interprète sera invoqué avec les arguments suivants
 175 points:
 176-
 177- interpréteur [option-arg] nomfichier arg ...
 178-
 179- où arg ... est la série de mots pointée par l'argument argv
 180 de execve (), à partir de argv [1].
 181 -
 182- Pour une utilisation portable, facultatif-arg devrait soit être absent, soit être
 183- spécifié comme un seul mot (c.-à-d. Qu'il ne devrait pas contenir de blanc
 184- espace);  voir NOTES ci-dessous.
 185- 
  186- Depuis Linux 2.6.28, le kernel autorise l'interpréteur d'un script 
  187- à lui-même être un script.  Cette autorisation est récursive, jusqu'à un 
  188- limite de quatre récurrences, pour que l'interprète soit un script 
  189- qui est interprété par un script, et ainsi de suite.
 -
 343: Scripts d'interprète
 344- Une longueur de ligne maximale de 127 caractères est autorisée pour la première
 345 lignes dans un script interprète.
 346-
 347- La sémantique de l'argument opt-arg d'un interprète
 Le script 348 varie selon les implémentations.  Sous Linux, la chaîne entière
 349- après le nom de l'interpréteur est passé en tant qu'argument unique à
 350 - l'interpréteur, et cette chaîne peut inclure un espace blanc.  Comment-
 Cependant, le comportement diffère sur certains autres systèmes.  Certains systèmes utilisent
 352- le premier espace blanc pour terminer l'argument optionnel.  Sur certains systèmes,
 353- un script d'interpréteur peut avoir plusieurs arguments et blanc-
 Les arguments 354-opt sont utilisés pour délimiter les arguments.
 355-
 356- Linux ignore les bits set-user-ID et set-group-ID sur les scripts.

Les nouveaux exécutables des systèmes d’exploitation de type Unix sont lancés par l’appel système execve (2). La page de execve de execve comprend:

 Interpreter scripts An interpreter script is a text file that has execute permission enabled and whose first line is of the form: #! interpreter [optional-arg] The interpreter must be a valid pathname for an executable which is not itself a script. If the filename argument of execve() specifies an interpreter script, then interpreter will be invoked with the following arguments: interpreter [optional-arg] filename arg... where arg... is the series of words pointed to by the argv argument of execve(). For portable use, optional-arg should either be absent, or be specified as a single word (ie, it should not contain white space); see NOTES below. 

Donc, dans ces limites (unix-like, optionnel-arg au maximum un mot), oui, les scripts shebang sont portables. Lisez la page de manuel pour plus de détails, y compris d’autres différences dans l’invocation entre les exécutables binarys et les scripts.