Comme vous le pensez, le comportement exact dépend du shell, mais un niveau de fonctionnalité de base est spécifié par POSIX.
La recherche et l'exécution de commandes pour le langage de commande shell standard (dont la plupart des shells implémentent un sur-ensemble) ont beaucoup de cas, mais nous ne sommes intéressés pour le moment que par le cas où PATH
est utilisé. Dans ce cas:
la commande doit être recherchée à l'aide de la variable d'environnement PATH comme décrit dans Variables d'environnement XBD
et
Si la recherche réussit:
[...]
le shell exécute l'utilitaire dans un environnement utilitaire séparé avec des actions équivalentes à l'appel de la execl()
fonction [...] avec l' argument path défini sur le chemin d'accès résultant de la recherche.
En cas d'échec, l'exécution échoue et un code de sortie de 127 est renvoyé avec un message d'erreur.
Ce comportement est conforme à la execvp
fonction, en particulier. Toutes les exec*
fonctions acceptent le nom de fichier d'un programme à exécuter, une séquence d'arguments (qui sera celle argv
du programme), et peut-être un ensemble de variables d'environnement. Pour les versions utilisant la PATH
recherche, POSIX définit que :
Le fichier d' arguments est utilisé pour construire un nom de chemin qui identifie le nouveau fichier image de processus [...] le préfixe de chemin pour ce fichier est obtenu par une recherche dans les répertoires passés comme variable d'environnement PATH
Le comportement de PATH est défini ailleurs comme:
Cette variable doit représenter la séquence de préfixes de chemin que certaines fonctions et utilitaires appliquent lors de la recherche d'un fichier exécutable connu uniquement par un nom de fichier. Les préfixes doivent être séparés par un <colon> (':'). Lorsqu'un préfixe de longueur non nulle est appliqué à ce nom de fichier, une <barre oblique> doit être insérée entre le préfixe et le nom de fichier si le préfixe ne se termine pas par. Un préfixe de longueur nulle est une fonction héritée qui indique le répertoire de travail actuel. Il apparaît sous la forme de deux caractères adjacents ("::"), en tant que <colon> initial précédant le reste de la liste, ou en tant que <colon> de fin après le reste de la liste. Une application strictement conforme doit utiliser un nom de chemin réel (tel que.) Pour représenter le répertoire de travail actuel dans PATH.La liste doit être recherchée du début à la fin, en appliquant le nom de fichier à chaque préfixe, jusqu'à ce qu'un fichier exécutable avec le nom spécifié et les autorisations d'exécution appropriées soit trouvé . Si le chemin recherché contient une <barre oblique>, la recherche dans les préfixes de chemin ne doit pas être effectuée. Si le nom de chemin commence par une <slash>, le chemin spécifié est résolu (voir Résolution de nom de chemin ). Si PATH n'est pas défini ou est défini sur null, la recherche de chemin est définie par l'implémentation.
C'est un peu dense, donc un résumé:
- Si le nom du programme contient une
/
(barre oblique, U + 002F SOLIDUS), traitez-le comme un chemin d'accès de la manière habituelle et ignorez le reste de ce processus. Pour le shell, ce cas ne se pose techniquement pas (car les règles du shell l'auront déjà traité).
- La valeur de
PATH
est divisée en morceaux à chaque deux-points, puis chaque composant est traité de gauche à droite. En tant que cas spécial (historique), un composant vide d'une variable non vide est traité comme .
(le répertoire courant).
- Pour chaque composant, le nom du programme est ajouté à la fin avec une jointure
/
et l'existence d'un fichier de ce nom est vérifiée, et s'il en existe un, les autorisations d'exécution valides (+ x) sont également vérifiées. Si l'une de ces vérifications échoue, le processus passe au composant suivant. Sinon, la commande résout ce chemin et la recherche est effectuée.
- Si vous manquez de composants, la recherche échoue.
- S'il n'y a rien
PATH
ou s'il n'existe pas, faites ce que vous voulez.
Les vrais shells auront des commandes intégrées, qui se trouvent avant cette recherche, et souvent aussi des alias et des fonctions. Ceux-là n'interagissent pas avec PATH
. POSIX définit certains comportements autour de ceux-ci , et votre shell peut en avoir beaucoup plus.
Bien qu'il soit possible de compter exec*
pour faire la plupart de cela pour vous, le shell peut en pratique implémenter cette recherche lui-même, notamment à des fins de mise en cache, mais le comportement de cache vide devrait être similaire. Les coquilles ont une latitude assez large ici et ont des comportements subtilement différents dans les cas d'angle.
Comme vous l'avez trouvé, Bash utilise une table de hachage pour se souvenir des chemins complets des commandes qu'il a vu précédemment, et cette table est accessible avec la hash
fonction. La première fois que vous exécutez une commande, elle recherche et lorsqu'un résultat est trouvé, il est ajouté à la table, il n'est donc pas nécessaire de chercher la prochaine fois que vous l'essayez.
Dans zsh, en revanche, le full PATH
est généralement recherché au démarrage du shell. Une table de recherche est préremplie avec tous les noms de commande découverts afin que les recherches d'exécution ne soient généralement pas nécessaires (sauf si une nouvelle commande est ajoutée). Vous pouvez remarquer que cela se produit lorsque vous essayez de compléter par tabulation une commande qui n'existait pas auparavant.
Les shells très légers, par exemple dash
, ont tendance à déléguer autant de comportements que possible à la bibliothèque système et ne se soucient pas de se souvenir des chemins de commandes passés.
PATH
entrebash
etzsh
m'aide à résoudre ma confusion!