Pourquoi ne pas utiliser des shebangs sans chemin?
24
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?
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 execvevers le nouveau processus.
Le noyau n'effectue aucune interprétation sur le chemin dans execve(c'est aux fonctions d'encapsuleur comme execvppour effectuer la recherche PATH) ou dans un shebang (qui réoriente plus ou moins l' execveappel 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 :
L'appelant n'a pas à se soucier si un programme à exécuter est un script shell ou un binaire natif.
Le script lui-même spécifie l'interpréteur à utiliser, au lieu de l'appelant.
Le noyau utilise le nom du script dans les journaux.
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/envshebang .
¹ 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.
Non, le noyau ne nécessite pas de chemin absolu dans execveni dans le shebang bien que cela ait peu de sens d'avoir un chemin relatif dans un shebang.
Stéphane Chazelas
3
Pour tous ceux qui sont curieux de savoir comment "shebang réachemine l'appel execve en interne": cela fait en fait partie d'un mécanisme générique pour exécuter des interprètes sur les exécutables qui en ont besoin. Les exécutables ELF liés dynamiquement sont "interprétés" par /lib64/ld-linux-x86-64.so.2(voir la lddsortie). Linux le rend entièrement générique: la binfmtprise en charge (depuis 2.1.43) vous permet d'enregistrer des paires interprète-chemin / nombre-magique-ou-extension de fichier. Vous pouvez faire .exeinvoquer les PE32 winelorsque vous les exécutez, les fichiers Java et les fichiers jar java, etc. etc.
Peter Cordes
#! / usr / bin / env -S [shebang] était nécessaire pour que j'exécute le nœud sans connaître son chemin (en utilisant nvm - ce qui le place à un emplacement différent de celui auquel je m'attendais à l'origine).
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 PATHn'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 perlde 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 PATHvariable d'environnement. envtrouve (dans cet exemple) perldans PATHet utilise l' execve(2)appel système pour que le noyau exécute l' perlexé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.
La conversion en chemin complet est effectuée par le shell Merci, bien que ... l'exemple est-il censé illustrer cela? Comme je le vois, le shell est juste en cours d'exécution strace(converti /usr/bin/straceà un moment donné) avec 2 arguments.
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 commeexecvp
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.
la source
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 laldd
sortie). Linux le rend entièrement générique: labinfmt
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 PE32wine
lorsque vous les exécutez, les fichiers Java et les fichiers jarjava
, 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 celaPATH
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'unePATH
variable d'environnement.env
trouve (dans cet exemple)perl
dansPATH
et utilise l'execve(2)
appel système pour que le noyau exécute l'perl
exécutable.la source
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.
la source
strace
(converti/usr/bin/strace
à un moment donné) avec 2 arguments.