Linux / Commande dirname : extraire le répertoire d’un chemin
dirname extrait la partie répertoire d’un chemin en retirant son dernier composant. Par exemple, dirname /var/log/nginx/access.log affiche /var/log/nginx ; la commande traite une chaîne et ne vérifie ni l’existence du fichier ni celle de son parent.
Utilisez ce résultat pour préparer un chemin ou une étiquette. Pour obtenir le chemin absolu réellement résolu, traiter des liens symboliques ou confirmer l’accès à un répertoire, il faut effectuer une opération supplémentaire adaptée au besoin.
Extraire la partie répertoire
dirname /home/alice/rapport.txt
dirname relatif/documents/guide.pdf
dirname notes.txt
Les résultats sont respectivement /home/alice, relatif/documents et .. Le point est la représentation du répertoire courant quand l’entrée ne comporte aucun séparateur. Il ne signifie pas que notes.txt a été trouvé dans ce répertoire.
Le dernier composant peut être un nom de fichier ou de répertoire. Pour /home/alice/Documents/, dirname retire le séparateur final puis Documents, et retourne /home/alice. Il ne se base pas sur une extension pour deviner le type d’un objet.
chemin='/srv/documents/rapport annuel.pdf'
env QUOTING_STYLE=literal dirname -- "$chemin"
Les guillemets transmettent tout le chemin comme un seul argument. -- termine les options : un nom qui commence par un tiret reste une donnée. La variable GNU QUOTING_STYLE=literal rend explicite la sortie littérale ; le manuel GNU Coreutils 9.12 prévoit autrement des citations de type shell lorsque la sortie est un terminal. Les versions antérieures peuvent afficher ces noms autrement.
Comprendre les entrées particulières
| Entrée passée comme un argument | Résultat GNU courant | Interprétation |
|---|---|---|
/srv/app/config.ini |
/srv/app |
Retrait du dernier nom |
config.ini |
. |
Aucun séparateur dans l’entrée |
Chaîne vide '' |
. |
Un argument vide reste un argument |
/etc ou / |
/ |
Le résultat ne remonte pas au-delà de la racine |
/srv/app/// |
/srv |
Les séparateurs finaux ne représentent pas des noms supplémentaires |
../logs/app.log |
../logs |
Le chemin reste relatif |
/srv/app/../rapport.txt |
/srv/app/.. |
Les composants précédents ne sont pas résolus |
Ne confondez pas dirname '', qui reçoit une chaîne vide, avec dirname sans argument, qui échoue. Un script qui exige un véritable nom de fichier doit rejeter lui-même l’argument vide avant d’utiliser le résultat.
Le cas // dépend de la plate-forme : GNU peut conserver les deux séparateurs si leur signification y diffère de celle de /. De manière générale, dirname n’est pas un outil de conservation de la ponctuation d’origine. La spécification POSIX de dirname laisse aussi une latitude sur certains séparateurs redondants et composants point ; ne bâtissez pas une comparaison textuelle portable sur leur conservation exacte.
Traiter plusieurs chemins et les erreurs
dirname -- /srv/www/index.html /var/log/syslog /home/alice/fichier.txt
GNU dirname accepte plusieurs chemins et produit ici trois résultats : /srv/www, /var/log et /home/alice. Un tiret isolé n’est pas une instruction de lecture de l’entrée standard ; dirname -- - traite simplement ce nom sans séparateur et retourne un point.
Le statut de sortie est 0 en cas de réussite et non nul en cas d’erreur, par exemple une option inconnue ou un argument manquant. Pour un script destiné à plusieurs systèmes Unix, vérifiez les options disponibles avec dirname --help sur GNU ou la documentation de l’implémentation : la forme POSIX spécifie un seul opérande, tandis que les arguments multiples et -z sont des extensions GNU.
Une réussite porte sur le calcul de la chaîne. Elle ne garantit pas que le parent sera accessible, qu’un nouveau fichier pourra y être créé ou qu’un lien symbolique n’aura pas changé entre deux opérations.
Conserver des noms avec des sauts de ligne
Un chemin peut contenir des sauts de ligne. Une sortie à raison d’un résultat par ligne ne suffit alors plus pour distinguer les enregistrements. GNU -z, ou --zero, termine chaque résultat par un octet nul, nommé NUL, qui ne peut pas faire partie d’un nom de fichier Unix.
Enregistrez ce script complet sous afficher-parents.sh, puis exécutez-le avec Bash et GNU dirname. Il ne crée aucun répertoire ; printf %q affiche une représentation lisible des espaces et caractères spéciaux.
#!/usr/bin/env bash
if [ "$#" -eq 0 ]; then
printf '%s\n' 'Usage : bash afficher-parents.sh chemin [chemin...]' >&2
exit 64
fi
set -o pipefail
env QUOTING_STYLE=literal dirname -z -- "$@" |
while IFS= read -r -d '' parent; do
printf 'Parent : %q\n' "$parent"
done
bash afficher-parents.sh '/srv/rapport annuel.pdf' /tmp/archive.tar.gz
bash afficher-parents.sh $'/tmp/ligne1\nligne2/rapport.txt'
Le premier appel affiche les parents /srv et /tmp. Le second transmet un seul argument dont le répertoire contient un saut de ligne ; l’affichage échappé garde cette frontière visible. La lecture read -r -d '' consomme les enregistrements NUL sans interpréter les barres obliques inverses. L’option Bash pipefail permet au script de signaler aussi un échec du producteur dirname.
Pour un traitement par programme, gardez cette séparation NUL jusqu’au consommateur. Ne remplacez pas cette boucle par une division sur les espaces ou par une variable censée contenir des octets NUL : les variables Bash ne peuvent pas les conserver.
Préparer le parent d’un fichier de sortie
La préparation d’un répertoire est une action distincte de son calcul. Le script suivant ne crée que les répertoires parents, avec mkdir -p, et laisse le fichier final intact. Il exige un argument non vide terminé par un nom ordinaire, puis conserve le statut de toute erreur.
Enregistrez-le sous preparer-parent.sh. Il utilise Bash et GNU dirname ; les droits de création restent ceux du compte qui l’exécute.
#!/usr/bin/env bash
if [ "$#" -ne 1 ]; then
printf '%s\n' 'Usage : bash preparer-parent.sh chemin-du-fichier' >&2
exit 64
fi
sortie=$1
case "$sortie" in
''|*/|.|..|*/.|*/..)
printf '%s\n' 'Indiquez un chemin terminé par un nom de fichier.' >&2
exit 64 ;;
esac
parent=$(env QUOTING_STYLE=literal dirname -- "$sortie" && printf '.') || {
statut=$?
printf '%s\n' 'Impossible de calculer le répertoire parent.' >&2
exit "$statut"
}
parent=${parent%.}
parent=${parent%$'\n'}
mkdir -p -- "$parent" || {
statut=$?
printf '%s\n' 'Impossible de préparer le répertoire parent.' >&2
exit "$statut"
}
printf 'Répertoire préparé : %q\n' "$parent"
Pour essayer sans viser un dossier système, créez un nouvel espace temporaire et passez un chemin situé à l’intérieur :
espace=$(mktemp -d) || exit 1
bash preparer-parent.sh "$espace/exports/journal/rapport.txt"
test -d "$espace/exports/journal" && printf '%s\n' 'Parent présent'
test ! -e "$espace/exports/journal/rapport.txt" && printf '%s\n' 'Aucun fichier créé'
Vous devez obtenir le chemin du parent, puis les deux confirmations. Inspectez l’espace temporaire avant de le supprimer lorsque l’essai est terminé. Le script refuse un chemin terminé par une barre oblique, . ou .. ; ce choix appartient à cet exemple de fichier de sortie et ne change pas les règles de dirname.
Le point ajouté après dirname empêche la substitution de commande de supprimer les sauts de ligne du résultat. Le script retire ensuite le point ajouté et exactement le saut de ligne de sortie. Le guide de pwd dans Bash explique cette propriété des substitutions. Un simple parent=$(dirname -- "$sortie") convient à des chemins dont la partie parent ne finit pas par un saut de ligne, mais ne conserve pas tous les noms possibles.
Utilisez ce script avec des chemins que vous avez choisis et vérifiés. Ni dirname ni mkdir -p ne confinent une entrée à un répertoire autorisé : .., un chemin absolu et des liens symboliques peuvent conduire ailleurs. Pour un service acceptant des chemins non fiables, la politique d’accès et la protection contre les changements concurrents doivent être conçues au niveau de l’ouverture ou de la création du fichier.
Distinguer dirname, basename, pwd et realpath
| Commande | Question traitée | Limite à retenir |
|---|---|---|
dirname |
Quelle partie précède le dernier nom de cette chaîne ? | Ne valide pas le chemin |
basename |
Quel est le dernier nom ? | Ne vérifie pas non plus l’existence |
pwd |
Où se trouve le processus courant ? | Ne prend pas un chemin quelconque à transformer |
realpath |
Quel chemin canonique correspond à cette entrée ? | Vérifier les options d’existence et de traitement des liens |
chemin='/home/alice/docs/rapport.pdf'
parent=$(dirname -- "$chemin") || exit 1
nom=$(basename -- "$chemin") || exit 1
printf 'Parent : %s\nNom : %s\n' "$parent" "$nom"
Cet exemple ordinaire donne /home/alice/docs et rapport.pdf. Il illustre l’usage complémentaire de basename et de son retrait de suffixe, sans prétendre reconstruire à l’identique la chaîne originale avec ses séparateurs finaux ou redondants.
Pour connaître le répertoire du script, ne prenez pas automatiquement dirname "$0" pour un chemin absolu fiable. La valeur dépend de la manière d’invoquer le script ; l’appel par PATH, l’exécution via un lien ou le chargement par source nécessitent une politique explicite. La position du processus courant et l’emplacement d’un fichier de script sont deux informations différentes.
Comparer avec l’expansion du shell
chemin='/srv/www/index.html'
printf '%s\n' "${chemin%/*}"
dirname -- "$chemin"
Les deux lignes produisent /srv/www dans ce cas. L’expansion retire le plus court suffixe correspondant au motif /*, sans lancer dirname. Elle ne reproduit pas toutes ses règles :
chemin='rapport.txt'
printf 'Expansion : <%s>\n' "${chemin%/*}"
printf 'dirname : '; dirname -- "$chemin"
chemin='/srv/dossier/'
printf 'Expansion : <%s>\n' "${chemin%/*}"
printf 'dirname : '; dirname -- "$chemin"
Pour rapport.txt, l’expansion laisse rapport.txt, tandis que dirname donne un point. Pour /srv/dossier/, elle laisse /srv/dossier, tandis que dirname retourne /srv. À la racine, l’expansion peut aussi donner une chaîne vide. Choisissez l’expansion pour un format de chaîne maîtrisé ; utilisez dirname lorsque vous voulez ses règles sur des entrées variées.
Le manuel GNU de dirname décrit les options et le format de sortie. Si le résultat paraît surprenant, vérifiez d’abord la valeur exacte de l’argument et ses séparateurs finaux, puis contrôlez séparément l’existence et les droits du répertoire avant de l’utiliser.




