Pourquoi ne pas utiliser des shebangs sans chemin?

Réponses:

20

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.

Gilles 'SO- arrête d'être méchant'
la source
2
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).
TamusJRoyce
-S n'est disponible que depuis coreutils 8.30. Voir gitlab.com/gnuwget/wget/commit/… .
Tim Ruehsen rockdaboot
19

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.

Bruce Ediger
la source
4
$ 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.

Hauke ​​Laging
la source
1
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.
Alois Mahdal