Aller au contenu
Administration Linux medium

Liens physiques et symboliques sous Linux

20 min de lecture

Un lien donne un second nom à un fichier, sans le dupliquer. Linux en propose deux sortes, qui se ressemblent à l'usage mais n'ont rien de commun en interne : le lien physique, un vrai nom supplémentaire pour les mêmes données, et le lien symbolique, un simple panneau indicateur qui contient un chemin. Ce guide montre comment créer les deux avec ln, comment les distinguer par leur inode, comment repérer un lien brisé, et surtout comment éviter la commande qui efface silencieusement le contenu de la cible. Toutes les sorties viennent d'un test sur AlmaLinux 10.

  • Créer un lien physique et un lien symbolique avec ln
  • Distinguer les deux grâce à l'inode et au compteur de liens
  • Choisir lequel utiliser selon le besoin
  • Repérer et réparer un lien symbolique brisé
  • Éviter les quatre pièges qui font perdre des données ou du temps

Pour comprendre les liens, il faut d'abord défaire une idée intuitive : sous Linux, un fichier et son nom sont deux choses séparées.

Les données, les permissions, les dates et le propriétaire vivent dans une structure appelée inode, identifiée par un numéro unique sur le système de fichiers. Le nom, lui, n'est qu'une entrée dans un répertoire, qui pointe vers ce numéro d'inode.

Un répertoire, c'est donc un annuaire : il associe des noms à des numéros. Rien n'interdit à deux noms de désigner le même numéro, et c'est exactement ce qu'est un lien physique.

Fenêtre de terminal
ls -li rapport.txt
8591538 -rw-r--r--. 1 ansible ansible 17 Jul 23 10:04 rapport.txt

La première colonne, ajoutée par l'option -i, est le numéro d'inode. Le chiffre juste après les permissions, ici 1, est le compteur de liens : le nombre de noms qui désignent cet inode. Ces deux valeurs sont la clé de tout ce qui suit.

Un lien physique (hard link) ajoute une entrée d'annuaire vers un inode existant. Il ne copie rien.

Fenêtre de terminal
echo "contenu original" > rapport.txt
ln rapport.txt rapport-copie.txt
ls -li rapport.txt rapport-copie.txt
8591538 -rw-r--r--. 2 ansible ansible 17 Jul 23 10:04 rapport-copie.txt
8591538 -rw-r--r--. 2 ansible ansible 17 Jul 23 10:04 rapport.txt

Deux observations à faire ensemble. Le numéro d'inode est identique (8591538) : ce n'est pas une copie, c'est le même fichier. Et le compteur de liens est passé de 1 à 2, parce que deux noms le désignent désormais.

La conséquence suit logiquement : modifier l'un modifie l'autre, puisqu'il n'y a qu'un seul fichier.

Fenêtre de terminal
echo "ligne ajoutee" >> rapport-copie.txt
cat rapport.txt
contenu original
ligne ajoutee

Et supprimer un nom ne détruit rien tant qu'il en reste un autre :

Fenêtre de terminal
rm rapport.txt
ls -li rapport-copie.txt
cat rapport-copie.txt
8591538 -rw-r--r--. 1 ansible ansible 31 Jul 23 10:04 rapport-copie.txt
contenu original
ligne ajoutee

Le compteur est retombé à 1, les données sont intactes. C'est ce qui explique le fonctionnement réel de rm : la commande retire un nom et décrémente le compteur. Les données ne sont libérées que lorsque le compteur atteint zéro, et qu'aucun processus ne tient le fichier ouvert.

Puisque plusieurs noms peuvent coexister, autant savoir les retrouver. find sait chercher par numéro d'inode :

Fenêtre de terminal
stat -c 'liens=%h inode=%i' a.txt
find ~/lab-liens -inum 8591547
liens=3 inode=8591547
/home/ansible/lab-liens/a.txt
/home/ansible/lab-liens/b.txt
/home/ansible/lab-liens/c.txt

C'est le réflexe à avoir quand du et df semblent se contredire : un fichier compté plusieurs fois par du mais stocké une seule fois sur le disque est très souvent un lien physique.

Le lien physique a deux contraintes strictes, qui découlent directement de sa nature.

Fenêtre de terminal
ln dossier dossier-lien
ln: dossier: hard link not allowed for directory

Pas de lien physique vers un répertoire. L'interdiction protège le système : des répertoires se pointant mutuellement créeraient des boucles infinies dans l'arborescence, que les outils de parcours ne sauraient pas traiter.

Fenêtre de terminal
ln ~/rapport.txt /dev/shm/essai
ln: failed to create hard link '/dev/shm/essai' => '/home/ansible/rapport.txt':
Invalid cross-device link

Pas de lien physique entre deux systèmes de fichiers. Un numéro d'inode n'a de sens qu'à l'intérieur d'un système de fichiers donné : l'inode 8591538 de votre disque et celui d'une clé USB n'ont aucun rapport. Le message Invalid cross-device link est explicite une fois qu'on connaît la raison.

Un lien symbolique (symlink, ou lien souple) est un fichier à part entière, avec son propre inode, dont le contenu est simplement un chemin. Il s'agit d'un panneau qui dit « ce que tu cherches est là-bas ».

Fenêtre de terminal
echo "donnees" > cible.txt
ln -s cible.txt raccourci.txt
ls -li cible.txt raccourci.txt
8591540 -rw-r--r--. 1 ansible ansible 8 Jul 23 10:04 cible.txt
8591541 lrwxrwxrwx. 1 ansible ansible 9 Jul 23 10:04 raccourci.txt -> cible.txt

Tout diffère du cas précédent. Les inodes sont différents (8591540 et 8591541), le type de fichier est l en tête des permissions, et ls -l affiche la flèche vers la destination. La taille de 9 octets n'est pas un hasard : c'est la longueur de la chaîne cible.txt.

Les liens symboliques lèvent les deux limites du lien physique : ils traversent les systèmes de fichiers et pointent vers des répertoires. C'est pourquoi ils sont, de très loin, les plus utilisés.

Comme le lien symbolique ne contient qu'un chemin, rien ne garantit que ce chemin existe. Supprimez la cible, et le lien devient brisé (dangling) :

Fenêtre de terminal
rm cible.txt
ls -l raccourci.txt
cat raccourci.txt
lrwxrwxrwx. 1 ansible ansible 9 Jul 23 10:04 raccourci.txt -> cible.txt
cat: raccourci.txt: No such file or directory

Le lien est toujours là, ls l'affiche sans broncher, mais rien ne répond au bout. Deux tests permettent de faire la différence en script :

Fenêtre de terminal
test -e raccourci.txt && echo "la cible existe" || echo "lien brise"
test -L raccourci.txt && echo "c'est bien un lien"

-e suit le lien et échoue si la cible manque ; -L teste l'existence du lien lui-même. Un lien brisé répond donc « non » au premier et « oui » au second, ce qui les distingue d'un fichier réellement absent.

Pour balayer une arborescence entière, find a un prédicat dédié :

Fenêtre de terminal
find /opt -xtype l

-xtype l ne remonte que les liens dont la cible n'est pas un lien valide, c'est-à-dire les liens cassés. C'est la commande d'inventaire après une migration ou une désinstallation.

En pratique, le choix se fait presque toujours en faveur du symbolique. Le tableau ci-dessous résume les propriétés qui décident.

CritèreLien physiqueLien symbolique
Inodele même que la ciblele sien, distinct
Vers un répertoireimpossiblepossible
Vers un autre système de fichiersimpossiblepossible
Si la cible est suppriméeles données surviventle lien est brisé
Visible dans ls -lindiscernable d'un fichierflèche -> et type l
Cas d'usage typiquesauvegardes, déduplicationversions courantes, raccourcis de configuration

Le motif le plus répandu en administration est le lien symbolique de version : un chemin stable qui pointe vers la version en cours, qu'on redirige lors d'une mise à jour sans toucher aux scripts qui l'utilisent.

Fenêtre de terminal
ln -sfn /opt/app-2.4.1 /opt/app-courante

Les scripts référencent /opt/app-courante, et une mise à jour se résume à faire pointer le lien ailleurs. Notez l'option -n, dont la section suivante explique pourquoi elle n'est pas facultative.

Ces quatre comportements ne produisent aucune erreur explicite, ou un message qui induit en erreur. Ils méritent d'être vus une fois avant de les rencontrer en production.

C'est le plus grave, parce qu'il perd des données en silence derrière un message rassurant. La combinaison en cause est précise : un lien symbolique vers un répertoire, une barre oblique finale, et l'option -r.

Fenêtre de terminal
mkdir cible-dir && touch cible-dir/f1 cible-dir/f2
ln -s cible-dir lien-dir
rm -r lien-dir/
rm: cannot remove 'lien-dir/': Not a directory

Le message annonce un échec, le code de retour vaut 1, et pourtant :

Fenêtre de terminal
ls cible-dir | wc -l
0

Les deux fichiers ont disparu. La barre oblique a fait suivre le lien à rm, qui a vidé le répertoire visé, puis a échoué en tentant de supprimer le lien lui-même, d'où le message. Le lien et le répertoire survivent, leur contenu non.

ln -sf ne remplace pas un lien visant un répertoire

Section intitulée « ln -sf ne remplace pas un lien visant un répertoire »

Le réflexe pour rediriger un lien existant est ln -sf. Il fonctionne pour un lien vers un fichier, et échoue silencieusement pour un lien vers un répertoire.

Fenêtre de terminal
ln -s v1 courant
ln -sf v2 courant
readlink courant
v1

Le code de retour vaut 0, et pourtant courant pointe toujours vers v1. La commande a interprété courant comme le répertoire de destination et a créé un lien à l'intérieur de la cible :

Fenêtre de terminal
ls v1
v2

L'option -n (--no-dereference) corrige le comportement en traitant courant comme un lien et non comme un répertoire :

Fenêtre de terminal
ln -sfn v2 courant
readlink courant
v2

Retenez la forme ln -sfn comme forme par défaut pour rediriger un lien : elle est correcte dans tous les cas.

Vous pourriez croire durcir un lien en modifiant ses permissions. Sous Linux, cela n'a aucun effet.

Fenêtre de terminal
ls -l l.txt # lrwxrwxrwx, comme tous les liens
chmod -h 600 l.txt
echo $?
stat -c %a l.txt
0
777

Le code de retour vaut 0, aucun message n'apparaît, et les droits n'ont pas bougé. La raison est simple : le noyau Linux ne consulte jamais les permissions d'un lien symbolique, seules comptent celles de la cible. L'option -h existe pour la portabilité vers d'autres Unix qui, eux, en tiennent compte.

Ce qui protège réellement, c'est donc de régler les droits de la cible, ou ceux du répertoire qui contient le lien.

Copier un lien symbolique ne donne pas un lien symbolique :

Fenêtre de terminal
cp lien.txt copie.txt
test -L copie.txt && echo "lien" || echo "fichier regulier"
fichier regulier

cp a suivi le lien et copié le contenu de la cible. Pour préserver le lien en tant que tel, il faut -d (ou -a, qui l'inclut) :

Fenêtre de terminal
cp -d lien.txt copie.txt
test -L copie.txt && echo "lien preserve"

Le même raisonnement vaut pour les sauvegardes : tar et rsync préservent les liens par défaut, mais cp -r seul les aplatit, ce qui peut multiplier par dix la taille d'une arborescence pleine de liens.

Les liens ont longtemps servi de vecteur d'attaque, en particulier dans les répertoires partagés comme /tmp. Le noyau Linux embarque deux protections, actives par défaut sur les distributions modernes.

Fenêtre de terminal
sysctl fs.protected_hardlinks fs.protected_symlinks
fs.protected_hardlinks = 1
fs.protected_symlinks = 1

fs.protected_hardlinks interdit de créer un lien physique vers un fichier qu'on ne possède pas et pour lequel on n'a pas les droits d'écriture. Sans elle, un utilisateur pouvait créer un lien vers un fichier sensible, attendre qu'un processus privilégié en change les droits, et se retrouver avec un accès qu'il n'aurait jamais dû obtenir.

Fenêtre de terminal
sudo -u autreuser ln /tmp/fichier-root /tmp/lien-vole
ln: failed to create hard link '/tmp/lien-vole' => '/tmp/fichier-root':
Operation not permitted

Quelques commandes d'inventaire, utiles lors d'un audit ou d'une migration.

Fenêtre de terminal
# Tous les liens symboliques
find /opt -type l
# Uniquement les liens brisés
find /opt -xtype l
# Fichiers ayant plusieurs noms (liens physiques)
find /home -type f -links +1
# Parcourir en suivant les liens
find -L /opt -type f

Un lien qui ne fait pas ce qu'on attend tombe presque toujours dans l'un de ces cas. Le tableau les classe par symptôme observable, puisque c'est ce dont vous disposez au moment du problème.

SymptômeCause probableSolution
No such file or directory alors que ls affiche le lienLien brisé : la cible a disparu ou a été déplacéereadlink -f <lien> pour voir la destination, puis recréer le lien
Un lien créé fonctionne, puis casse après un déplacementLe lien a été créé avec un chemin relatifLe recréer en chemin absolu, ou déplacer les deux ensemble
hard link not allowed for directoryLien physique vers un répertoireUtiliser ln -s
Invalid cross-device linkLien physique entre deux systèmes de fichiersUtiliser ln -s
Operation not permitted sur un lnfs.protected_hardlinks : vous ne possédez pas la ciblePasser par le propriétaire, ou utiliser un lien symbolique
ln -sf rend 0 mais le lien pointe toujours au même endroitLa cible est un répertoire, un lien a été créé dedansUtiliser ln -sfn, et nettoyer le lien parasite créé
Le contenu d'un répertoire a disparu après un rmrm -r lien/ avec barre oblique finaleRestaurer depuis la sauvegarde ; ne jamais mettre de / final sur un lien
chmod sur un lien ne change rienLes droits d'un lien ne sont jamais consultés sous LinuxRégler les droits de la cible ou du répertoire parent
Une copie pèse bien plus lourd que l'originalcp -r a suivi les liens et dupliqué les ciblesUtiliser cp -a (ou -d) pour préserver les liens
  • Un fichier est un inode ; un nom n'est qu'une entrée de répertoire qui pointe vers lui.
  • Un lien physique est un nom de plus vers le même inode : même contenu, données conservées tant qu'un nom subsiste. Impossible vers un répertoire ou vers un autre système de fichiers.
  • Un lien symbolique contient un chemin. Il traverse les systèmes de fichiers, pointe vers des répertoires, et devient brisé si la cible disparaît.
  • ls -li tranche en une commande : inode identique pour un lien physique, type l et flèche pour un lien symbolique.
  • rm -r lien/ avec une barre oblique finale vide le répertoire cible en affichant Not a directory. Les trois autres formes sont sans danger.
  • Pour rediriger un lien, écrivez ln -sfn : sans -n, un lien vers un répertoire n'est pas remplacé mais dupliqué à l'intérieur.
  • chmod sur un lien ne sert à rien sous Linux, et cp sans -d copie la cible au lieu du lien.
  • fs.protected_hardlinks et fs.protected_symlinks sont des protections à conserver, même si leurs messages d'erreur ne les nomment pas.

Ce site vous est utile ?

Sachez que moins de 1% des lecteurs soutiennent ce site.

Je maintiens +700 guides gratuits, sans pub ni tracking. Un soutien, même symbolique, m'aide à couvrir l'hébergement et à garder ces ressources gratuites. Merci pour votre appui.

Le formulaire ne s'affiche pas ? Ouvrir Ko-fi dans un onglet.

Abonnez-vous et suivez mon actualité DevSecOps sur LinkedIn