Linux / Commande type : identifier la résolution d’un nom dans Bash

Dans Bash, type nom indique comment le shell interpréterait un nom de commande : alias, mot réservé, fonction, commande interne ou fichier exécutable. Utilisez type -a nom pour examiner les candidats masqués et type -t nom pour obtenir seulement la catégorie ; cette inspection n’exécute pas le programme recherché.

Lire le résultat dans le shell concerné

type est lui-même une commande interne de Bash. Ses réponses dépendent de la session : fonctions, alias, commandes internes activées, variable PATH et chemins mémorisés peuvent différer entre votre terminal, un script et une session lancée avec un autre utilisateur.

La syntaxe générale ci-dessous est une notation documentaire, avec des options facultatives entre crochets :

type [-afptP] nom [nom ...]

Commencez par des noms dont vous voulez connaître l’interprétation :

type cd
type if
type printf
type ls

La forme sans option produit une explication lisible, éventuellement avec la définition d’une fonction ou la valeur d’un alias. Le texte peut être traduit ; les catégories renvoyées par -t sont mieux adaptées à un traitement automatique.

Catégorie Interprétation
alias Un remplacement de texte appliqué lors de la lecture de la commande, si l’expansion des alias est active.
keyword Un mot réservé du langage, comme if ou for.
function Une fonction définie dans le shell.
builtin Une commande interne exécutée par Bash.
file Un fichier exécutable identifié pour ce nom.

Un résultat keyword ne signifie pas que le mot puisse être exécuté seul : if a besoin d’une construction syntaxique complète. Plus généralement, type décrit la résolution d’un nom ; il n’analyse pas toutes les possibilités d’une ligne de commande avec arguments, redirections ou mots cités.

Voir la catégorie et les candidats cachés

Obtenir un mot avec -t

type -t cd
type -t if
type -t printf

Dans un Bash où ces noms ne sont pas masqués, les résultats attendus sont builtin, keyword et builtin. Un alias ou une fonction peut changer la réponse pour certains noms. Si le nom est introuvable, -t ne produit pas de catégorie et le statut est non nul.

Énumérer les possibilités avec -a

type -a printf
type -a test
type -a ls

printf et test peuvent exister à la fois comme commandes internes et comme programmes externes. -a permet de découvrir ce qu’un résultat unique ne montre pas. La présence d’un candidat dans la liste ne signifie pas que toutes les formes d’invocation sélectionneront ce candidat.

Les règles ordinaires d’une commande simple recherchent une fonction, puis une commande interne, puis un fichier, sous réserve de l’analyse préalable des alias et de la syntaxe. Un chemin contenant une barre oblique, builtin, command ou les règles d’un autre mode de shell changent le contexte. La documentation Bash sur la recherche et l’exécution détaille cette phase.

Différencier -p, -P et une recherche fraîche dans PATH

PATH est la liste des répertoires utilisés pour rechercher les programmes par nom. -p affiche un chemin lorsque la résolution sélectionne un fichier ; une réponse vide peut donc être normale pour une commande interne ou un nom masqué par une fonction.

type -p printf
type -p cd
type -P printf

-P, avec un P majuscule, recherche un fichier même si un alias, une fonction ou un builtin porte ce nom. Il ne change pas le comportement de la prochaine invocation de printf : demander un chemin n’exécute ni ne reconfigure la commande.

La recherche peut aussi rencontrer le cache de commandes de Bash, appelé table de hachage. Si un chemin y est mémorisé, -p et -P peuvent le retourner plutôt que le premier fichier qu’un nouveau parcours de PATH trouverait. Pour énumérer les fichiers du chemin sans utiliser cette table :

type -a -p printf

La combinaison -a -p ignore les alias, fonctions et builtins dans la sortie et effectue une recherche dans PATH. Elle est utile pour comparer les fichiers disponibles à la résolution du nom dans la session.

Option Question traitée
-t Quelle catégorie est sélectionnée pour ce nom ?
-a Quels candidats correspondent au même nom ?
-p Quel chemin afficher si le nom est résolu comme fichier ?
-P Quel fichier rechercher malgré une fonction, un alias ou un builtin de même nom ?
-a -p Quels fichiers trouve un parcours de PATH sans la table de hachage ?
-f Quelle serait la réponse en omettant la recherche des fonctions ?

-f n’écarte pas les alias et ne force pas une recherche de fichier. Il peut donc révéler un builtin sous une fonction sans être équivalent à -P. Ces nuances sont précisées dans la référence des commandes internes Bash.

Démasquer un alias ou une fonction sans modifier la session

Examiner l’alias avant de le contourner

type ls
alias ls

Si aucun alias ls n’est défini, la seconde commande peut échouer ; ce n’est pas la preuve que le programme externe manque. Une définition d’alias peut ajouter des arguments ou remplacer la commande par une expression plus complexe.

Écrire \ls empêche l’expansion d’un alias portant ce nom, mais ne contourne pas une fonction ls. Un chemin explicite vers un exécutable évite ces deux résolutions par nom ; vérifiez d’abord le chemin présent sur votre système, au lieu de supposer que /usr/bin convient partout.

Les alias sont développés à la lecture du code. Dans un Bash non interactif, leur expansion est normalement désactivée, sauf activation de expand_aliases. Le résultat d’un script peut donc différer du terminal. La documentation officielle des alias Bash décrit aussi pourquoi définir puis utiliser un alias dans une même commande composée est trompeur.

Observer une fonction qui masque un builtin

Exécutez cet exercice complet dans Bash. Tout se déroule dans un sous-shell : un éventuel alias printf y est retiré, puis une fonction temporaire du même nom est définie. Les réglages et définitions de la session parente restent disponibles à la sortie.

(
  builtin unalias printf 2>/dev/null || :
  function printf {
    builtin printf '%s\n' 'Fonction de démonstration'
  }
  builtin type -t printf
  \printf
  command printf '%s\n' 'Commande interne'
)

Les trois lignes attendues sont :

function
Fonction de démonstration
Commande interne

\printf appelle encore la fonction : la barre oblique inverse protège le nom contre un alias, pas contre la recherche de fonction. command printf omet la fonction et atteint ici le builtin. Il ne force donc pas nécessairement le programme externe. Le mot builtin utilisé dans la fonction appelle explicitement le builtin et évite une récursion.

Pour consulter les options du printf interne, utilisez ensuite help printf, comme l’explique le guide de l’aide intégrée à Bash. Vous n’avez pas à supprimer une fonction réelle de votre session pour comprendre la différence.

Diagnostiquer un chemin mémorisé ou un environnement différent

Pour un nom concret tel que git, vous pouvez inspecter la table et comparer les fichiers trouvés :

hash -t git
type -a git
type -a -p git
printf '%s\n' "$PATH"

hash -t git peut échouer si aucun emplacement n’a été mémorisé. Si une entrée devient obsolète après une modification des fichiers ou un enregistrement explicite avec hash -p, hash -d git efface cette seule entrée ; hash -r efface toute la table. Ce sont des modifications du cache du shell courant, sans suppression du programme.

En revanche, affecter une valeur à PATH vide déjà les chemins mémorisés dans Bash. Il serait donc inexact d’attribuer systématiquement une ancienne réponse à un cache conservé après cette affectation. La référence officielle de hash précise cette règle.

Si les réponses diffèrent encore, comparez le shell et ses fichiers de démarrage, les fonctions et alias, le compte utilisateur et le PATH réellement utilisés. Un environnement lancé par sudo, un service ou une autre session peut chercher ailleurs. Reproduisez le diagnostic dans le contexte concerné avant de modifier une configuration.

Classer un nom dans un script Bash complet

Créez un nouveau fichier classer-commande.sh avec ce contenu. Le script attend un seul argument non vide, traite cet argument comme un nom et ne l’exécute pas :

#!/usr/bin/env bash
if [ "$#" -ne 1 ] || [ -z "$1" ]; then
  printf 'Utilisation : bash classer-commande.sh nom\n' >&2
  exit 64
fi

if nature=$(builtin type -t -- "$1"); then
  printf '%s : %s\n' "$1" "$nature"
else
  printf 'Nom non trouvé dans ce Bash : %s\n' "$1" >&2
  exit 1
fi

Lancez-le explicitement avec Bash :

bash classer-commande.sh cd
bash classer-commande.sh if
bash classer-commande.sh __nom_absent_pour_essai__

Dans un environnement ordinaire non personnalisé, les deux premières commandes affichent cd : builtin et if : keyword. Si le troisième nom n’existe pas, le script affiche un diagnostic sur la sortie d’erreur et termine avec 1. Un appel sans argument ou avec un nombre incorrect d’arguments termine avec 64, code choisi pour l’usage de ce script.

Le script inspecte son propre Bash. Un nouveau processus Bash ne reprend pas automatiquement les alias et toutes les fonctions locales du terminal parent. Pour comprendre la résolution dans ce terminal, exécutez directement type -a nom dans celui-ci, sans attendre d’un script séparé qu’il reproduise cet état.

Le statut d’un appel type avec plusieurs noms échoue si l’un d’eux manque, même si d’autres ont produit une réponse. Pour une décision par nom, interrogez-les séparément. Ne parsez pas les phrases de la sortie ordinaire pour déterminer leur catégorie.

Choisir entre type, command -v et which

Outil Usage pertinent
type nom Expliquer la résolution dans Bash, avec une sortie lisible.
type -a nom Comparer les candidats, y compris ceux masqués par d’autres définitions.
command -v nom Tester la résolution d’un nom dans le shell, notamment dans un script visant les interfaces POSIX.
which nom Rechercher un emplacement selon les possibilités de l’implémentation ; un outil externe ne connaît pas spontanément tout l’état interne du shell parent.

Dans un script, un test de statut évite de dépendre d’une phrase traduite :

if command -v git >/dev/null 2>&1; then
  printf '%s\n' 'Le nom git est résolu dans ce shell.'
else
  printf '%s\n' 'Le nom git est introuvable dans ce shell.' >&2
fi

Une résolution réussie ne garantit ni la bonne version du programme, ni ses dépendances, ni les permissions nécessaires à l’opération envisagée. Vérifiez ensuite le comportement ou la version avec un essai adapté, sans transformer automatiquement la sortie de type en code à exécuter.