Est-il possible d'avoir un shebang qui, au lieu de spécifier un chemin vers un interprète, a le nom de l'interpréteur et laisse le shell le trouver via $ PATH?
Sinon, y a-t-il une raison à cela?
Est-il possible d'avoir un shebang qui, au lieu de spécifier un chemin vers un interprète, a le nom de l'interpréteur et laisse le shell le trouver via $ PATH?
Sinon, y a-t-il une raison à cela?
Réponses:
La recherche PATH est une fonctionnalité de la bibliothèque C standard dans l'espace utilisateur, tout comme les variables d'environnement en général. Le noyau ne voit pas les variables d'environnement sauf lorsqu'il passe sur un environnement de l'appelant execve
vers le nouveau processus.
Le noyau n'effectue aucune interprétation sur le chemin dans execve
(c'est aux fonctions d'encapsuleur comme execvp
pour effectuer la recherche PATH) ou dans un shebang (qui réoriente plus ou moins l' execve
appel en interne). Vous devez donc mettre le chemin absolu dans le shebang¹. L' implémentation originale de shebang n'était que quelques lignes de code et n'a pas été considérablement développée depuis.
Dans les premières versions d'Unix, le shell faisait le travail de s'appeler lui-même lorsqu'il remarquait que vous appeliez un script. Shebang a été ajouté dans le noyau pour plusieurs raisons (résumant la justification de Dennis Ritchie :
Les shebangs sans chemin nécessiteraient soit d'augmenter le noyau pour accéder aux variables et processus d'environnement PATH
, soit de faire exécuter au noyau un programme en espace utilisateur qui effectue la recherche PATH. La première méthode nécessite d'ajouter une quantité disproportionnée de complexité au noyau. La deuxième méthode est déjà possible avec un #!/usr/bin/env
shebang .
¹ Si vous mettez un chemin relatif, il est interprété par rapport au répertoire courant du processus (pas le répertoire contenant le script), ce qui n'est guère utile dans un shebang.
execve
ni dans le shebang bien que cela ait peu de sens d'avoir un chemin relatif dans un shebang.
/lib64/ld-linux-x86-64.so.2
(voir la ldd
sortie). Linux le rend entièrement générique: la binfmt
prise en charge (depuis 2.1.43) vous permet d'enregistrer des paires interprète-chemin / nombre-magique-ou-extension de fichier. Vous pouvez faire .exe
invoquer les PE32 wine
lorsque vous les exécutez, les fichiers Java et les fichiers jar java
, etc. etc.
Il se passe plus de choses que ce que l'on voit. #!
les lignes sont interprétées par le noyau Unix ou Linux, #!
n'est pas un aspect des shells. Cela signifie que cela PATH
n'existe pas vraiment au moment où le noyau décide quoi exécuter.
La façon la plus courante de ne pas savoir quel exécutable exécuter, ou d'appeler perl
de manière portable ou similaire, est d'utiliser #!/usr/bin/env perl
. Le noyau s'exécute /usr/bin/env
, qui hérite d'une PATH
variable d'environnement. env
trouve (dans cet exemple) perl
dans PATH
et utilise l' execve(2)
appel système pour que le noyau exécute l' perl
exécutable.
$ strace sleep 1
execve("/usr/bin/sleep", ["sleep", "1"], [/* 99 vars */]) = 0
La conversion en chemin complet est effectuée par le shell (plus général: dans l'espace utilisateur). Le noyau attend un nom de fichier / chemin d'accès auquel il peut accéder directement.
Si vous voulez que le système trouve votre exécutable en parcourant la variable PATH, vous pouvez réécrire votre shebang en tant que #!/usr/bin/env EXEC
.
Mais dans ce cas également, ce n'est pas le noyau qui effectue la recherche.
strace
(converti /usr/bin/strace
à un moment donné) avec 2 arguments.