Récupérer des fichiers supprimés avec rm -rf
Vous avez lancé rm -rf sur le mauvais chemin ? Arrêtez les écritures, démontez le système et suivez les options de récupération réellement disponibles sur ext4.
À faire pendant les 60 premières secondes
Deux actions déterminent si vous pourrez récupérer des fichiers supprimés avec rm -rf. Elles doivent toutes deux être effectuées avant même d’ouvrir un moteur de recherche. Arrêtez toute écriture sur ce système de fichiers. Retirez-le ensuite de l’utilisation en le démontant ou en le remontant en lecture seule.
rm n’efface rien. Il supprime l’entrée de répertoire, puis marque l’inode et les blocs de données du fichier comme libres. Les octets sont toujours présents sur le périphérique. Ils y restent jusqu’à ce que l’allocateur de blocs attribue ces blocs à autre chose et qu’une écriture les écrase. Chaque seconde pendant laquelle le système de fichiers reste monté et actif, un daemon écrit une ligne dans un journal ou une base de données vide une page. L’une ou l’autre de ces écritures peut utiliser les blocs que vous voulez récupérer.
Les premières commandes doivent donc arrêter les écritures, et non récupérer les fichiers.
sudo systemctl stop nginx postgresql
sudo umount /mnt/dataSi umount renvoie umount: /mnt/data: target is busy., recherchez ce qui maintient le système de fichiers ouvert.
sudo fuser -vm /mnt/data
sudo lsof +D /mnt/dataSi vous ne pouvez pas le libérer, remontez-le en lecture seule. Un montage en lecture seule empêche les nouvelles allocations, ce qui couvre l’essentiel de vos besoins.
sudo mount -o remount,ro /mnt/dataSi le chemin supprimé se trouvait sur le système de fichiers racine, la procédure est plus complexe. sudo mount -o remount,ro / échoue généralement avec mount: /: cannot remount /dev/vda1 read-only., car des processus en cours utilisent des fichiers ouverts en écriture et le kernel ne les fermera pas de force. Sur un VPS, la solution pratique consiste à utiliser le mode rescue ou recovery de votre fournisseur : il démarre un système live distinct avec votre disque attaché, mais non monté. Toutes les commandes ci-dessous s’exécutent alors sur un périphérique sur lequel aucun processus n’écrit.
Une règle s’applique à l’ensemble de ce guide. N’écrivez jamais les fichiers récupérés, une image disque ou un outil nouvellement installé sur le système de fichiers depuis lequel vous effectuez la récupération. Attachez un second volume ou envoyez la sortie vers une autre machine via SSH.
Pourquoi la récupération après rm -rf sur ext4 est généralement impossible
Définissez vos attentes avant d’installer quoi que ce soit. Vérifiez le système de fichiers utilisé :
lsblk -fSur ext4, le système de fichiers par défaut de presque toutes les images VPS, l’emplacement des données d’un fichier est stocké dans son inode sous forme d’arbre d’extents. Un extent est un enregistrement indiquant que le bloc logique N de ce fichier commence au bloc physique M et s’étend sur L blocs. Les petits fichiers stockent jusqu’à quatre de ces enregistrements directement dans l’inode. Les fichiers plus volumineux pointent vers des blocs supplémentaires qui contiennent le reste de l’arbre.
Lorsque le dernier lien vers un fichier disparaît, ext4 parcourt cet arbre, rend chaque extent à l’allocateur de blocs et efface l’arbre de l’inode. L’inode est ensuite marqué comme libre et reçoit une heure de suppression. Les données elles-mêmes ne sont pas modifiées. Le seul enregistrement indiquant où se trouvaient ces données a été effacé.
C’est la différence avec ext3, où un inode supprimé conservait suffisamment d’informations pour qu’un outil comme ext3grep puisse le suivre. Vous pouvez toujours lister les inodes supprimés sur ext4 :
sudo debugfs -R lsdel /dev/vdb1debugfs ouvre le device en lecture seule, sauf si vous passez -w. Cette opération est donc sûre sur un device démonté et ne coûte rien à tenter. Les inodes seront listés. C’est lors de l’extraction de l’un d’eux que cela s’arrête, car la table des blocs que cet inode contenait a été effacée. dump n’a donc plus rien à suivre.
Deux outils tentent de contourner ce problème en lisant le journal. Le journal est une structure circulaire de taille fixe qu’ext4 utilise pour préserver la cohérence des métadonnées après un crash. Il peut encore contenir une ancienne copie de l’inode datant d’avant la suppression. extundelete et ext4magic le recherchent tous les deux. Vérifiez la taille utilisée :
sudo dumpe2fs -h /dev/vdb1 | grep -i journalLe journal ne contient que des métadonnées et sa taille est réduite. Les écritures courantes le parcourent donc rapidement en boucle. Sur un serveur en fonctionnement, la période pendant laquelle l’inode précédant la suppression existe encore se mesure en minutes. Aucun de ces outils n’est activement maintenu et aucun n’est fourni dans toutes les distributions. Considérez-les comme une solution peu probable. Exécutez-les sur un device démonté ou sur une image disque, et ne soyez pas surpris s’ils ne renvoient aucun résultat.
Si lsblk -f indique xfs, la situation n’est pas meilleure, car XFS ne propose pas non plus de procédure de récupération des fichiers supprimés prise en charge. L’ordre des options ci-dessous ne change rien.
Le fichier est-il toujours ouvert par un processus en cours d’exécution ?
C’est la seule méthode de récupération présentée ici qui offre de bonnes chances de réussite. C’est pourquoi vous ne devez pas redémarrer le service qui utilisait le fichier.
Un fichier n’est réellement supprimé que lorsque deux compteurs atteignent zéro : le nombre d’entrées de répertoire qui pointent vers son inode et le nombre de descripteurs de fichier ouverts. rm ramène le premier compteur à zéro. Si un processus maintient encore le fichier ouvert, le second compteur n’est pas nul. L’inode et ses blocs sont donc toujours alloués, et les données restent lisibles.
Recherchez les fichiers ouverts dont le nombre de liens est tombé à zéro :
sudo lsof +L1+L1 signifie lister les fichiers ouverts dont le nombre de liens est inférieur à 1. Chaque résultat indique le processus, le numéro du descripteur de fichier, un NLINK de 0 et un chemin qui se termine par (deleted). Relevez le PID et le numéro du descripteur, puis utilisez /proc :
sudo ls -l /proc/1234/fdUne entrée ressemble à 3 -> /var/log/app/events.log (deleted). Ce lien permet toujours d’accéder aux données. Copiez-les vers un autre système de fichiers :
sudo cp /proc/1234/fd/3 /mnt/rescue/events.logUtilisez cp, et non mv. L’ouverture de /proc/1234/fd/3 vous donne une nouvelle référence vers le même inode, en commençant à l’offset zéro. Vous récupérez ainsi l’intégralité du fichier, et non seulement la partie située après la position actuelle d’écriture.
Deux limites doivent être connues. Une arborescence de répertoire supprimée ne peut pas être restaurée de cette manière, car seuls les fichiers individuels qu’un processus avait ouverts sont encore conservés. De plus, une copie d’un fichier de base de données effectuée pendant une écriture du moteur est cohérente après un crash. Prévoyez donc d’exécuter la procédure de récupération propre au moteur au lieu de considérer cette copie comme saine. Les entrées que lsof affiche avec mem à la place d’un numéro de descripteur sont memory-mapped. Elles ne disposent donc d’aucune entrée /proc/<pid>/fd à partir de laquelle effectuer la copie.
Disposez-vous d’un snapshot sur btrfs, ZFS ou LVM ?
Si le système de fichiers prend des snapshots, les fichiers supprimés se trouvent encore dans l’un d’eux, sans modification. Cela fonctionne uniquement si un snapshot existait avant la suppression. Rien de ce que vous créez maintenant ne permet de revenir en arrière.
btrfs conserve les snapshots sous forme de subvolumes :
sudo btrfs subvolume list /Parcourez le snapshot et copiez les chemins nécessaires avec cp -a. Préférez la copie de chemins individuels à la restauration de tout un subvolume, car une restauration supprime également tout ce qui a été écrit depuis la création du snapshot.
ZFS expose chaque snapshot sous forme de répertoire en lecture seule :
zfs list -t snapshot
ls /tank/data/.zfs/snapshot/Le répertoire .zfs est masqué et n’apparaît pas dans un ls simple de la racine du dataset, mais vous pouvez y accéder en indiquant son nom. Copiez les fichiers depuis ce répertoire. zfs rollback restaure l’ensemble du dataset et détruit tous les snapshots plus récents que celui que vous indiquez. Gardez donc cette commande en dernier recours.
Les snapshots LVM sont des volumes copy-on-write de taille fixe :
sudo lvs
sudo mount -o ro /dev/vg0/data-snap /mnt/snapMontez-le en lecture seule et copiez les fichiers. Vérifiez lvs avant de lui faire confiance, car un snapshot LVM qui remplit l’espace qui lui est alloué est invalidé par le kernel. Une fois cela fait, son contenu est perdu.
Un snapshot n’est pas une sauvegarde. Il se trouve sur le même disque ou dans le même pool que l’original et subit donc les mêmes pannes. Il est très efficace pour annuler une erreur commise il y a deux minutes, ce qui correspond exactement au besoin ici.
Récupération par carving avec PhotoRec, à partir d’une image et jamais du disque en production
Si aucune des solutions précédentes ne s’applique, il reste le carving : analyser le périphérique brut à la recherche de signatures d’octets qui marquent le début d’un type de fichier connu, puis écrire les données qui suivent. Le carving lit uniquement les données des fichiers. Les noms de fichiers, l’arborescence, les horodatages et les propriétaires sont des métadonnées du système de fichiers. C’est précisément ce que rm a détruit. Rien de tout cela ne peut donc être récupéré. Vous obtenez des fichiers nommés f0384512.jpg dans un répertoire de sortie numéroté, puis vous les triez manuellement.
Deux règles déterminent si cette méthode peut fonctionner.
Premièrement, créez une image du périphérique avant d’y appliquer un autre outil. Sur Debian et Ubuntu, le paquet est gddrescue et le binaire qu’il installe est ddrescue.
sudo apt update && sudo apt install -y gddrescue testdisk
sudo ddrescue -n /dev/vdb1 /mnt/rescue/vdb1.img /mnt/rescue/vdb1.map/mnt/rescue doit se trouver sur un autre périphérique, avec au moins autant d’espace libre que la partition en contient. lsblk -b affiche les tailles exactes en octets. Le fichier map permet de reprendre une copie interrompue au lieu de recommencer depuis le début. Une fois l’image créée, vous pouvez essayer ultérieurement un autre outil sur exactement les mêmes octets. C’est impossible si le premier outil a écrit sur le disque.
Deuxièmement, indiquez le fichier image comme source à l’outil de récupération.
sudo photorec /d /mnt/rescue/recup /mnt/rescue/vdb1.imgphotorec ouvre un menu textuel. Sélectionnez la partition, puis le type de système de fichiers, les signatures de fichiers à rechercher et enfin le répertoire de destination. Réduisez cette liste de signatures aux types de fichiers que vous avez réellement perdus avant de commencer. La liste par défaut recherche tous les types et vous transmet des dizaines de milliers de fragments à trier.
testdisk, fourni dans le même paquet, possède sa propre fonction de récupération de fichiers supprimés. Elle prend uniquement en charge FAT, exFAT, NTFS et ext2. Sur ext4, cela laisse photorec.
Attendez-vous à ce que les fichiers fragmentés soient récupérés de manière incorrecte. Le carving suppose que les blocs d’un fichier sont contigus. Un fichier dont l’allocateur a réparti les blocs sur le disque est donc soit mal réassemblé, soit complètement ignoré. Les fichiers multimédias sont généralement bien récupérés, car ils possèdent des en-têtes caractéristiques. Le texte brut, les fichiers de configuration et le code source sont mal récupérés, car aucune signature d’octets ne marque le début d’un script shell.
L’espace parasite : comment le mauvais chemin a été supprimé
Presque tous les accidents avec rm -rf sont des problèmes de shell. rm reçoit une liste de chemins et les supprime l’un après l’autre. Il ne sait jamais ce que vous vouliez faire.
Le cas classique est un espace unique :
rm -rf /home/deploy/app /old
rm -rf /home/deploy/app/oldLa première ligne contient deux arguments. Elle supprime l’application, puis /old. Si /old n’existe pas, rm n’affiche absolument rien, car -f masque l’erreur indiquant que le fichier est absent. L’absence de message ne confirme pas la réussite.
Le deuxième cas est une variable non protégée par des guillemets qui contient un espace :
dir="/srv/my app"
rm -rf $dirLe shell découpe la valeur au niveau des espaces. rm reçoit donc /srv/my et app comme deux chemins distincts. Écrit sous la forme rm -rf "$dir", il s’agit d’un seul chemin.
Le troisième cas est une variable vide, généralement parce que la commande qui devait lui affecter une valeur a échoué :
rm -rf "$TARGET"/*Lorsque TARGET n’est pas définie, cela se développe en rm -rf /*. GNU rm refuse cette forme seule : rm -rf / affiche rm: it is dangerous to operate recursively on '/' et s’arrête. La forme avec joker ne bénéficie pas de cette protection, car le shell remplace /* par une liste de chemins réels de premier niveau avant l’exécution de rm. / n’en fait pas partie, et la protection ne se déclenche donc jamais.
Habitudes qui évitent la prochaine erreur
- Entourez de guillemets chaque variable utilisée comme chemin. Écrivez
"$dir"à chaque fois, y compris dans les tests et les boucles. - Arrêtez-vous si la valeur est vide.
rm -rf "${TARGET:?TARGET is not set}"/*arrête le shell avec votre message avant le démarrage derm, lorsqueTARGETn’est pas définie ou est vide. Placezset -euo pipefailen haut de tout script qui supprime des fichiers. - Ajoutez
--one-file-system. Cette option indique àrmd’ignorer tout répertoire situé sur un autre système de fichiers que celui correspondant à l’argument fourni. Ainsi, une suppression récursive ne peut pas parcourir un volume de sauvegarde monté ou un bind mount. - Ne supprimez pas les fichiers avec root. Un compte de service ne peut supprimer que les éléments dont il est propriétaire. C’est tout l’intérêt de faire fonctionner chaque service avec son propre utilisateur sans privilèges. Si vous ne savez pas ce qu’un compte peut atteindre, lire les bits de permission dans une sortie de ls permet de le vérifier avec une seule commande.
- Affichez la liste avant d’agir. Dans un script, construisez les chemins, appliquez-leur
printf '%s\n', lisez la sortie, puis supprimez-les lors d’un second passage. - Gardez une commande de corbeille à portée de main.
sudo apt install trash-clivous fournittrash-put,trash-list,trash-restoreettrash-empty. Les fichiers supprimés sont déplacés vers~/.local/share/Trash, ettrash-empty 30supprime tout ce qui date de plus de trente jours.
Créer un alias de rm vers trash-put semble être l’étape suivante évidente, mais c’est un piège. L’alias crée un réflexe qui échoue sur le serveur suivant s’il n’en dispose pas. De plus, les alias ne s’appliquent pas dans les scripts, là où les erreurs coûteuses se produisent. Saisissez plutôt trash-put volontairement.
La seule récupération qui fonctionne à chaque fois
Tout ce qui précède repose sur une possibilité. Une sauvegarde n’en est pas une.
Deux conditions rendent une sauvegarde réelle. Elle s’exécute selon une planification sans que vous ayez à y penser. Vous l’avez restaurée au moins une fois. Un repository dont personne n’a jamais effectué de restauration relève de la croyance, car les problèmes qui le rendent inutilisable — un chemin incorrect dans la liste des éléments inclus ou un mot de passe de repository que personne n’a noté — n’apparaissent que le jour où vous en avez besoin.
Avec restic, une restauration nécessite deux commandes.
restic -r /srv/restic-repo snapshots
restic -r /srv/restic-repo restore latest --target /mnt/rescue --include /srv/appdataRestaurez dans un répertoire vide plutôt que par-dessus le chemin actif. Vous pourrez ainsi comparer les deux avant de remettre quoi que ce soit en place. Configurer des sauvegardes restic sur un VPS décrit la configuration du repository et le systemd timer qui l’exécute.
Avec Borg :
borg list /srv/borg-repo
borg extract /srv/borg-repo::daily-2026-08-08 srv/appdataLes chemins dans une archive Borg sont enregistrés sans le slash initial. Ainsi, srv/appdata correspond, tandis que /srv/appdata ne correspond à rien. borg extract écrit dans le répertoire de travail courant. Utilisez donc cd vers un répertoire de travail temporaire au préalable.
Si vous n’avez pas encore choisi entre les deux, la comparaison entre restic et Borg présente la déduplication et les repositories append-only. Cette propriété empêche un serveur compromis de supprimer son propre historique de sauvegardes. Les deux outils conviennent. La mauvaise réponse consiste à n’en exécuter aucun.
Un nouveau serveur est le moment le moins coûteux pour mettre cela en place, avant d’y stocker quoi que ce soit qu’il serait dommage de perdre. Les dix premières minutes sur un nouveau VPS est l’endroit où effectuer ce travail, avec la configuration de SSH et du firewall.
Ajoutez ensuite une tâche récurrente à votre calendrier : restaurez chaque mois un répertoire du repository dans /tmp, puis lisez les fichiers. Cette seule habitude vaut mieux que tous les outils de cette page.
FAQ
Puis-je restaurer un fichier supprimé sur ext4 ?
En général, non. Lorsque le dernier lien vers un fichier disparaît, ext4 efface l’arbre des extents de l’inode. Plus rien sur le disque n’indique donc où se trouvaient les données. extundelete et ext4magic recherchent une ancienne copie de cet inode dans le journal ext4. Cela n’est utile que si la suppression date de quelques minutes et que le système de fichiers est resté inactif depuis. Aucun de ces projets n’est activement maintenu. Exécutez l’un ou l’autre sur un périphérique démonté ou une image disque, jamais sur un système de fichiers monté. Vérifiez d’abord ce sur quoi vous travaillez avec sudo dumpe2fs -h /dev/vdb1 | grep -i journal.
Un service a toujours le fichier supprimé ouvert. Puis-je le récupérer ?
Oui, et c’est le meilleur cas. Tant qu’un processus maintient le fichier ouvert, son inode et ses blocs de données restent alloués. Les données sont donc toujours lisibles. Ne redémarrez pas le service, car la fermeture du dernier descripteur termine la suppression. Exécutez sudo lsof +L1 pour lister les fichiers ouverts dont le nombre de liens est égal à 0. Notez le PID et le numéro du descripteur de fichier, puis copiez les données avec /proc et sudo cp /proc/1234/fd/3 /mnt/rescue/events.log. Écrivez la copie sur un autre système de fichiers. Les entrées affichant mem à la place d’un numéro de descripteur sont mappées en mémoire. Elles ne fournissent aucun chemin /proc/<pid>/fd depuis lequel effectuer la copie.
Pourquoi créer une image du disque plutôt que d’exécuter l’outil de récupération dessus ?
Parce que tout outil doit écrire sa sortie quelque part. Une écriture sur le système de fichiers que vous récupérez peut utiliser les blocs libres qui contiennent encore vos données. Copiez d’abord la partition sur un autre périphérique avec sudo ddrescue -n /dev/vdb1 /mnt/rescue/vdb1.img /mnt/rescue/vdb1.map, puis indiquez à photorec le fichier image. L’image permet aussi d’essayer ultérieurement un autre outil sur exactement les mêmes octets. C’est impossible dès qu’une écriture a écrasé les données originales.
La commande rm -rf / détruit-elle encore un système Linux ?
La commande seule ne le fait pas. GNU rm la refuse et affiche rm: it is dangerous to operate recursively on '/'. Les formes dangereuses sont celles qui arrivent par un autre moyen. rm -rf "$TARGET"/* avec TARGET non défini se développe en rm -rf /*. Le shell transmet alors à rm une liste de répertoires racine réels, dont aucun n’est /. La protection ne se déclenche donc jamais. Écrivez plutôt "${TARGET:?TARGET is not set}". Le shell s’arrête avant l’exécution de rm.
Un snapshot de système de fichiers est-il une sauvegarde ?
Non. Un snapshot btrfs ou ZFS se trouve dans le même pool que les données qu’il protège. Une panne du disque ou la destruction du pool les supprime donc tous les deux. Un snapshot LVM pose un problème supplémentaire : sa taille est fixe. Lorsqu’il est plein, le kernel l’invalide et son contenu est perdu. Les snapshots sont excellents pour annuler une suppression datant de deux minutes. Pour tout le reste, conservez un repository sur un matériel distinct.