Développement

Supprimer des fichiers et des dossiers via SSH : le guide complet.

Les commandes utiles, la limite d’arguments qui fait échouer rm, quatre méthodes mesurées sur cent mille fichiers et l’espace disque qui ne revient pas.

17 septembre 2026Par Amine14 min de lecture
Terminal affichant les commandes find, lsof et truncate évoquées dans le guide
Article publié le 17 septembre 2026 · dernière modification le 17 septembre 2026

Il n’y a pas de corbeille en SSH. Sur un serveur, rm ne déplace rien : il retire l’entrée du répertoire et marque les blocs comme réutilisables. Aucune confirmation, aucun historique, aucun « annuler ». La seule chose qui vous sauve, c’est une sauvegarde antérieure — ou le fait de ne pas avoir lancé la commande.

Ce guide part de cette contrainte. Il donne les commandes utiles, mais surtout ce qui les entoure : comment mesurer avant d’agir, pourquoi rm * échoue passé un certain nombre de fichiers, quelle méthode est réellement la plus rapide sur cent mille fichiers, et pourquoi l’espace disque ne revient parfois pas après une suppression réussie. Les chiffres qui suivent ont été mesurés, pas estimés.

Les six commandes qui couvrent presque tous les cas

Avant les subtilités, l’essentiel. Ces six formes suffisent à traiter la très grande majorité des suppressions sur un serveur web.

Commandes de suppression et ce qu’elles font exactement
CommandeEffetQuand l’employer
rm fichier.logSupprime un fichier. Échoue si c’est un dossier.Cas unitaire, le plus sûr.
rm -i *.logDemande confirmation pour chaque fichier.Quand le motif vous semble juste sans en être certain.
rmdir cacheSupprime un dossier uniquement s’il est vide.Filet de sécurité : refuse d’agir si le dossier contient quelque chose.
rm -r cacheSupprime un dossier et son contenu, en demandant pour les fichiers protégés.Suppression récursive avec un minimum de garde-fou.
rm -rf cacheSupprime sans question et sans erreur si la cible n’existe pas.Scripts et automatisation. Jamais tapé à la main sur un chemin long.
find . -name "*.tmp" -deleteSupprime par critère, sans passer par l’interpréteur de commandes.Dès que la sélection dépasse ce qu’un motif simple exprime.

Une remarque sur -f. Beaucoup de tutoriels l’ajoutent par réflexe. Il fait deux choses : il supprime les fichiers en lecture seule sans demander, et il tait les erreurs. Cette seconde partie est la dangereuse. rm -rf /var/www/site/uplaods — avec la faute de frappe — ne dit rien et renvoie un code de succès. Sans -f, la même commande aurait affiché « aucun fichier ou dossier de ce nom », et vous auriez relu votre chemin.

Mesurer avant de supprimer

La plupart des suppressions catastrophiques commencent par une mauvaise estimation de ce qu’on croit supprimer. Trois commandes évitent cela, et elles coûtent quelques secondes.

Reconnaître le terrain avant d’agir
QuestionCommandeCe que vous apprenez
Qu’est-ce qui pèse lourd ici ?du -sh * | sort -h | tail -20Les vingt entrées les plus volumineuses du dossier courant, triées.
Combien de fichiers vais-je toucher ?find . -name "*.log" | wc -lLe compte exact, avant de remplacer | wc -l par -delete.
Lesquels exactement ?find . -name "*.log" -printf "%TY-%Tm-%Td %10s %p\n" | sort | head -40Date, taille et chemin des premiers concernés.
Quel espace vais-je récupérer ?find . -name "*.log" -print0 | du --files0-from=- -ch | tail -1Le total réel des fichiers sélectionnés.
Y a-t-il un lien symbolique ?find . -maxdepth 2 -type l -lsUn rm -rf sur un lien vers un montage partagé détruit la cible.

La règle qui en découle tient en une phrase : toute commande de suppression s’écrit d’abord sans le verbe de suppression. On remplace -delete par -print, ou rm par echo rm. On lit la sortie. Puis on rappelle la ligne et on remplace. Ce détour coûte dix secondes et il a sauvé plus de sites que n’importe quelle sauvegarde.

Supprimer par critère : ce que find apporte

Un motif comme *.log ne dit rien de l’âge, de la taille ni de la profondeur. find exprime ces trois dimensions, et il les combine.

Sélections courantes sur un serveur web
BesoinCommande
Journaux de plus de trente joursfind /var/log/site -name "*.log" -mtime +30 -delete
Fichiers de plus de 100 Mofind . -type f -size +100M -printf "%10s %p\n" | sort -rn
Cache du jour uniquementfind var/cache -mindepth 1 -maxdepth 1 -mtime 0 -exec rm -rf {} +
Dossiers vides, en remontantfind . -depth -type d -empty -delete
Tout sauf un dossierfind . -mindepth 1 -maxdepth 1 ! -name "uploads" -exec rm -rf {} +
Sans franchir un point de montagefind . -xdev -name "*.tmp" -delete

Deux détails techniques méritent d’être compris plutôt que copiés.

-depth impose à find de traiter le contenu d’un dossier avant le dossier lui-même. Sans lui, -type d -empty -delete ne supprime qu’un niveau : le dossier parent n’était pas vide au moment où find l’a examiné. Avec lui, une arborescence entière de dossiers vides disparaît en une passe.

-exec rm -rf {} + et -exec rm -rf {} \; ne sont pas équivalents. Le point-virgule lance un processus rm par fichier trouvé ; le signe plus regroupe autant de chemins que la limite du système l’autorise et lance beaucoup moins de processus. Sur dix mille fichiers, l’écart se compte en dizaines de secondes.

La limite que personne n’anticipe : rm * sur des milliers de fichiers

Un jour, sur un dossier de cache qui a grossi, cette commande répond :

$ rm -f *
-bash: /bin/rm: Argument list too long

Ce n’est pas rm qui refuse. C’est le noyau. L’interpréteur de commandes développe * en la liste complète des noms de fichiers et la passe au programme ; cette liste ne peut pas dépasser une taille fixée par le système. Sur la machine où ce guide a été écrit :

$ getconf ARG_MAX
2097152

Soit deux mégaoctets pour l’ensemble des arguments et des variables d’environnement. En pratique, avec des noms de fichiers d’une douzaine de caractères, la rupture a été observée entre cinquante mille et cent mille arguments : cinquante mille passaient, cent mille déclenchaient l’erreur. Le seuil exact dépend de la longueur des noms et de la taille de votre environnement — ce qui explique pourquoi la même commande passe sur un serveur et échoue sur un autre.

Trois contournements fonctionnent, et aucun ne consiste à augmenter la limite.

Supprimer un très grand nombre de fichiers
MéthodeCommandePourquoi ça marche
Supprimer le dossier entierrm -rf cache && mkdir cacheUn seul argument passé à rm. Attention aux droits et au propriétaire à recréer.
find avec -deletefind cache -mindepth 1 -deletefind appelle le noyau fichier par fichier, sans liste d’arguments.
xargs par lotsfind cache -type f -print0 | xargs -0 -r rm -fxargs découpe lui-même en lots sous la limite.

Le -print0 associé à -0 n’est pas décoratif : il sépare les chemins par un octet nul au lieu d’un saut de ligne, seul moyen fiable de traiter des noms contenant des espaces, des apostrophes ou des retours à la ligne. Le -r évite que xargs lance rm sans argument quand la recherche ne trouve rien.

Quatre méthodes, mesurées

La question « laquelle est la plus rapide » revient souvent, et les réponses trouvées en ligne sont rarement chiffrées. Voici une mesure. Protocole : une arborescence de fichiers de 64 octets répartis par lots de deux cents dans des sous-dossiers à deux niveaux, recréée avant chaque essai, sur le même système de fichiers, machine au repos.

Durée de suppression en secondes, mesurée sur trois volumes
Méthode10 000 fichiers50 000 fichiers100 000 fichiers
rm -rf0,13 s0,47 s0,98 s
find -delete0,10 s0,48 s1,01 s
find | xargs rm0,13 s0,58 s1,17 s
Perl unlink0,18 s0,74 s1,71 s
0 s0,61,21,8 10 00050 000100 000 rm -rf find -delete find | xargs rm perl unlink

Trois conclusions se dégagent, et la première est la plus utile : entre les trois méthodes du système, l’écart ne dépasse pas vingt pour cent. Choisir find -delete plutôt que rm -rf pour gagner du temps ne se justifie pas ; on choisit find parce qu’il exprime un critère, pas parce qu’il va plus vite.

Deuxième conclusion : les trois croissent linéairement avec le nombre de fichiers. Le coût est dominé par les appels système d’un déréférencement par fichier, pas par le volume de données. Supprimer cent mille fichiers de 64 octets prend le même temps que cent mille fichiers de plusieurs mégaoctets — ce qui explique pourquoi vider un dossier de vignettes est lent alors qu’il ne pèse presque rien.

Troisième conclusion : passer par un langage de script coûte cher. Perl est soixante-quinze pour cent plus lent à cent mille fichiers, parce qu’il parcourt l’arborescence en mémoire avant de supprimer. Une version en Python ou en PHP se comporterait de la même façon. Sur un serveur, la commande native reste le bon outil.

Un mot d’honnêteté sur ces chiffres : ils ont été relevés sur un système de fichiers rapide, machine peu chargée. Sur un disque mécanique, un NFS ou un hébergement mutualisé chargé, les valeurs absolues peuvent être dix à cent fois plus élevées. Ce qui reste valable, ce sont les rapports entre méthodes et la linéarité, pas les durées elles-mêmes. Une seule commande a échappé à la mesure : rsync --delete, absente de la machine d’essai. Mieux vaut le dire que produire un chiffre inventé.

Quand l’espace disque ne revient pas

Voici un scénario qui coûte des heures de recherche. Vous supprimez un journal de plusieurs gigaoctets qui remplissait le disque. ls confirme qu’il a disparu. df affiche toujours le disque plein.

Ce n’est pas un bug, et il n’y a rien à réparer. Sous Linux, un fichier ne disparaît réellement que lorsque deux conditions sont réunies : plus aucune entrée de répertoire n’y mène, et plus aucun processus ne le tient ouvert. Un serveur web, une base de données ou un service de journalisation qui écrivait dans ce fichier en garde le descripteur. Le fichier devient invisible mais ses blocs restent réservés.

La démonstration, mesurée :

espace libre avant                    : 27 538 Mo
après rm, descripteur toujours ouvert : 27 538 Mo  (le fichier n'existe plus)
après fermeture du descripteur        : 27 658 Mo
espace rendu à la fermeture           : 120 Mo

Le fichier pesait cent vingt mégaoctets. La suppression n’a rien rendu. La fermeture du descripteur a tout rendu d’un coup. Pour identifier le coupable sur un serveur :

$ lsof +L1
COMMAND   PID   USER   FD   TYPE  SIZE/OFF NLINK   NODE NAME
nginx    1247   www    12w  REG  2147483648     0 393218 /var/log/nginx/access.log (deleted)

La colonne NLINK à zéro est la signature : plus aucun lien, mais un descripteur ouvert. Deux issues possibles. La propre consiste à demander au service de rouvrir ses journaux — systemctl reload nginx, ou le signal que documente le service. La brutale consiste à redémarrer le processus. Et la solution qui évite le problème consiste à ne pas supprimer un journal actif : on le vide sans le supprimer.

# vide le fichier sans toucher au descripteur
$ : > /var/log/nginx/access.log
# ou, équivalent et plus explicite
$ truncate -s 0 /var/log/nginx/access.log

L’espace est rendu immédiatement, le service continue d’écrire dans le même fichier, aucun redémarrage n’est nécessaire. C’est la manière correcte de traiter un journal qui remplit un disque en production.

Les cinq suppressions qui cassent un site

Ces cinq cas reviennent dans les incidents que nous reprenons. Aucun n’est théorique.

1. L’espace involontaire après la barre oblique

rm -rf /var/www/ site au lieu de rm -rf /var/www/site. L’interpréteur voit deux cibles : le dossier complet, puis un dossier site relatif. La protection --preserve-root, active par défaut sur les distributions courantes, ne couvre que / exactement — pas /var/www/. La seule défense est la relecture avant validation.

2. La variable vide dans un script

rm -rf "$DOSSIER_CIBLE/"*   # si la variable est vide : rm -rf /*

Un script qui n’a pas trouvé sa variable d’environnement supprime la racine. Deux lignes l’évitent, et elles devraient ouvrir tout script de déploiement :

set -euo pipefail
: "${DOSSIER_CIBLE:?la variable DOSSIER_CIBLE doit être définie}"

Le set -u fait échouer le script sur toute variable non définie ; la seconde ligne produit un message explicite plutôt qu’un chemin vide.

3. Le lien symbolique pris pour un dossier

rm -rf uploads quand uploads est un lien vers un stockage partagé monté ailleurs. La commande suit le lien et vide le stockage — y compris pour les autres sites qui l’utilisent. find . -maxdepth 2 -type l -ls avant toute suppression récursive répond à la question.

4. Le fichier caché oublié

rm -rf site/* laisse intacts .env, .htaccess, .git et .well-known, parce que le motif * ne correspond pas aux noms commençant par un point. On croit avoir vidé le dossier ; les secrets de connexion à la base y sont toujours. C’est un problème de sécurité autant que de propreté.

5. Le cache supprimé avec ses droits

rm -rf var/cache && mkdir var/cache recrée le dossier avec le propriétaire et les droits de l’utilisateur connecté, pas ceux du serveur web. Le site répond alors une erreur cinq cents sans que rien n’apparaisse dans les journaux applicatifs. mkdir -p var/cache && chown www-data:www-data var/cache ferme le cas — après avoir relevé le propriétaire d’origine avec stat -c "%U:%G %a".

Vider un dossier sans le supprimer

C’est le besoin réel derrière la plupart des suppressions sur un site : vider un cache, des sessions, des exports temporaires, sans perdre le dossier ni ses droits.

Vider un dossier : ce que chaque forme couvre
CommandeFichiers cachésDroits du dossier
rm -rf dossier/*Non traitésConservés
rm -rf dossier/{*,.*}Traités, mais génère des erreurs sur . et ..Conservés
find dossier -mindepth 1 -deleteTraités proprementConservés
rm -rf dossier && mkdir dossierTraitésPerdus, à rétablir

La troisième forme est celle à retenir. -mindepth 1 exclut le dossier lui-même du résultat : son contenu part, lui reste, avec son propriétaire et ses permissions intacts. C’est la commande que nous mettons dans les scripts de purge de cache.

Rendre une suppression réversible

La meilleure défense n’est pas une commande plus prudente, c’est de ne pas supprimer tout de suite. Trois pratiques, par ordre d’efficacité.

Déplacer avant de supprimer. mv suspect /tmp/a-supprimer-2026-09-17/ puis, quelques jours plus tard, quand le site tourne toujours, la vraie suppression. Le déplacement dans le même système de fichiers est instantané quel que soit le volume, parce qu’il ne fait que réécrire une entrée de répertoire. Ce délai est la seule chose qui distingue une erreur d’un incident.

Archiver ce qui part. tar -czf /tmp/cache-2026-09-17.tar.gz var/cache && find var/cache -mindepth 1 -delete. L’archive coûte peu sur du cache compressible et se supprime à son tour dans un mois.

Refuser la commande destructive à la main. Dans un fichier de profil : alias rm='rm -I --preserve-root'. Le -I majuscule demande une seule confirmation quand plus de trois fichiers sont concernés — assez peu intrusif pour ne pas être contourné, assez présent pour arrêter une faute de frappe. Les scripts, eux, appellent /bin/rm explicitement et ne sont pas affectés.

Sur un hébergement mutualisé

Une partie de ce guide suppose un accès root. Sur un hébergement mutualisé, plusieurs choses changent. L’accès SSH est parfois restreint à un interpréteur limité, sans find ni lsof. Les processus des autres comptes sont invisibles, donc lsof +L1 ne montrera pas le service qui tient votre journal ouvert. Le redémarrage d’un service n’est pas à votre main. Et la limite d’arguments est la même pour tous, mais le nombre de processus simultanés autorisé est souvent bas, ce qui rend -exec {} \; particulièrement pénalisant.

Dans ce contexte, deux réflexes : préférer find -delete, qui n’ouvre aucun processus supplémentaire, et vider les journaux par truncate plutôt que les supprimer, puisque vous ne pourrez pas recharger le service.

La liste à relire avant toute suppression en production

  1. Où suis-je ? pwd. Une commande relative lancée du mauvais dossier est la première cause d’accident.
  2. Qu’est-ce que je vais toucher ? La même commande avec -print au lieu de -delete, ou echo devant rm.
  3. Combien ? | wc -l. Un ordre de grandeur inattendu signale un motif trop large.
  4. Des liens symboliques dans le chemin ? find . -maxdepth 2 -type l -ls.
  5. Le service peut-il tenir un descripteur ? S’il s’agit d’un journal actif, truncate et non rm.
  6. Quels droits à rétablir ? stat -c "%U:%G %a" dossier, noté avant de supprimer le dossier lui-même.
  7. Ai-je une sauvegarde datée d’avant cette commande ? Si la réponse est « je crois », la réponse est non.
  8. Puis-je déplacer au lieu de supprimer ? Dans le doute, mv, et la suppression dans huit jours.

Ces huit points prennent moins de deux minutes. Une restauration de sauvegarde en prend plusieurs heures, quand elle est possible — et l’expérience montre qu’elle ne l’est pas toujours, parce que la sauvegarde datait d’après l’incident, ou parce que personne n’avait vérifié qu’elle se restaurait.

C’est d’ailleurs le vrai sujet derrière ce guide. Les commandes s’apprennent en une heure. Ce qui distingue un serveur qu’on peut réparer d’un serveur qu’on doit reconstruire, c’est une maintenance qui vérifie ses sauvegardes et une infogérance qui garde trace de qui a lancé quoi, et quand.

Maintenance de site internet

Organisez prévention, correction, sauvegarde, traçabilité et reprise autour d’un périmètre explicite.

Découvrir cette expertise