SSD Nodes Learn 🎉 VPS da $5.50/mese
Guide Matt ConnorDi Matt Connor · Aggiornato 2026-08-13

Come recuperare file eliminati con rm -rf su ext4

Hai eseguito rm -rf sul percorso sbagliato? Smetti subito di scrivere sul disco e scopri quali opzioni di recupero esistono davvero su ext4.

Cosa fare nei primi sessanta secondi

Due azioni determinano se è possibile recuperare i file eliminati con rm -rf, e vanno eseguite prima di aprire un motore di ricerca. Smettere di scrivere su quel filesystem. Poi rimuoverlo dall'uso, smontandolo oppure rimontandolo in sola lettura.

rm non cancella nulla. Rimuove la voce della directory, quindi contrassegna l'inode e i blocchi dati del file come liberi. I byte sono ancora presenti sul dispositivo. Rimangono lì finché l'allocatore dei blocchi non assegna quei blocchi a qualcos'altro e quel processo non li sovrascrive. Ogni secondo in cui il filesystem resta montato e occupato, un daemon scrive una riga di log oppure un database esegue il flush di una pagina. Entrambe le operazioni possono usare i blocchi che si desidera recuperare.

Per questo, i primi comandi devono arrestare le scritture, non recuperare i file.

sudo systemctl stop nginx postgresql
sudo umount /mnt/data

Se umount restituisce umount: /mnt/data: target is busy., individuare il processo che mantiene aperto il filesystem.

sudo fuser -vm /mnt/data
sudo lsof +D /mnt/data

Se non è possibile liberarlo, rimontarlo in sola lettura. Un mount in sola lettura impedisce nuove allocazioni, che è la misura principale necessaria.

sudo mount -o remount,ro /mnt/data

Se il percorso eliminato si trovava sul filesystem root, la procedura è più complessa. sudo mount -o remount,ro / in genere fallisce con mount: /: cannot remount /dev/vda1 read-only., perché i processi in esecuzione mantengono aperti file in scrittura e il kernel non li forza alla chiusura. Su un VPS, la soluzione pratica è usare la modalità rescue o recovery del provider: avvia un sistema live separato con il disco collegato ma non montato. A quel punto, ogni comando seguente viene eseguito su un dispositivo su cui nessuno sta scrivendo.

Una regola vale per l'intera guida. Non scrivere mai i file recuperati, un'immagine disco o uno strumento appena installato sul filesystem dal quale stai recuperando i dati. Collega un secondo volume oppure invia l'output a un'altra macchina tramite SSH.

Perché il recupero con rm -rf su ext4 è quasi sempre impossibile

Definite le aspettative prima di installare qualsiasi strumento. Verificate quale filesystem state utilizzando:

lsblk -f

Su ext4, il filesystem predefinito in quasi tutte le immagini VPS, la posizione dei dati di un file è memorizzata nel suo inode sotto forma di albero di extent. Un extent è un record che indica che il blocco logico N del file inizia al blocco fisico M e occupa L blocchi. I file piccoli memorizzano fino a quattro record direttamente nell'inode. I file più grandi puntano a blocchi aggiuntivi che contengono il resto dell'albero.

Quando viene rimosso l'ultimo link a un file, ext4 percorre l'albero, restituisce ogni extent all'allocatore dei blocchi e cancella l'albero dall'inode. L'inode viene quindi marcato come libero e gli viene assegnato un timestamp di eliminazione. I dati non vengono modificati. L'unico record della posizione in cui si trovavano viene cancellato.

Questa è la differenza rispetto a ext3, in cui un inode eliminato conservava informazioni sufficienti perché uno strumento come ext3grep potesse seguirne le tracce. Su ext4 è comunque possibile elencare gli inode eliminati:

sudo debugfs -R lsdel /dev/vdb1

debugfs apre il dispositivo in sola lettura, a meno che non venga passato -w, quindi l'operazione è sicura su un dispositivo non montato e non comporta rischi. Gli inode verranno elencati. Il recupero del contenuto di un inode è il punto in cui la procedura si interrompe, perché la mappa dei blocchi che l'inode conteneva è stata cancellata e dump non ha più nulla da seguire.

Due strumenti tentano di aggirare il problema leggendo il journal. Il journal è un buffer circolare di dimensione fissa che ext4 usa per mantenere coerenti i metadati dopo un arresto anomalo. Può contenere ancora una copia precedente dell'inode, risalente a prima dell'eliminazione. extundelete e ext4magic eseguono entrambi una ricerca nel journal. Verificate la dimensione disponibile:

sudo dumpe2fs -h /dev/vdb1 | grep -i journal

Il journal contiene solo metadati ed è di dimensioni ridotte, quindi la normale attività di scrittura lo sovrascrive rapidamente. Su un server in esecuzione, l'intervallo durante il quale l'inode precedente all'eliminazione è ancora disponibile si misura in minuti. Nessuno dei due strumenti è sottoposto a manutenzione attiva e nessuno dei due è disponibile nei pacchetti di tutte le distribuzioni. Considerateli tentativi con poche probabilità di successo, eseguiteli su un dispositivo non montato o su un'immagine disco e non sorprendetevi se non restituiscono alcun risultato.

Se lsblk -f restituisce xfs, la situazione non è migliore, perché anche per XFS non esiste uno strumento di undelete supportato. L'ordine delle opzioni riportate di seguito non cambia.

Il file è ancora aperto in un processo in esecuzione?

Questo è l'unico metodo di recupero descritto in questa pagina con buone probabilità di successo. Per questo motivo non bisogna riavviare il servizio che usava il file.

Un file è realmente eliminato solo quando entrambi i contatori arrivano a zero: il numero di voci di directory che puntano al suo inode e il numero di file descriptor aperti. rm porta a zero il primo contatore. Se un processo mantiene aperto il file, il secondo contatore non è zero. L'inode e i relativi blocchi sono quindi ancora allocati e i dati sono ancora leggibili.

Individuare i file aperti il cui numero di link è sceso a zero:

sudo lsof +L1

+L1 significa elencare i file aperti con un numero di link inferiore a 1. Ogni risultato mostra il processo, il numero del file descriptor, un NLINK di 0 e un percorso che termina con (deleted). Usare il PID e il numero del descriptor con /proc:

sudo ls -l /proc/1234/fd

Una voce ha un aspetto simile a 3 -> /var/log/app/events.log (deleted). Quel link consente ancora di accedere ai dati. Copiarli su un filesystem diverso:

sudo cp /proc/1234/fd/3 /mnt/rescue/events.log

Usare cp, non mv. L'apertura di /proc/1234/fd/3 crea un nuovo handle sullo stesso inode, iniziando dall'offset zero. In questo modo si ottiene l'intero file, non soltanto la parte successiva alla posizione corrente del writer.

È importante conoscere due limitazioni. Un albero di directory eliminato non può essere recuperato in questo modo, perché restano disponibili soltanto i singoli file che un processo aveva aperto. Inoltre, un file di database copiato mentre il motore sta eseguendo una scrittura è una copia coerente rispetto a un crash. È quindi necessario prevedere il ripristino tramite gli strumenti del motore, invece di considerare la copia integra. Le voci che lsof mostra con mem al posto del numero di descriptor sono mappate in memoria. Per queste voci non esiste alcuna voce /proc/<pid>/fd da cui copiare i dati.

Hai uno snapshot su btrfs, ZFS o LVM?

Se il filesystem supporta gli snapshot, i file eliminati si trovano ancora all'interno di uno snapshot, invariati. Questo è utile solo se lo snapshot esisteva prima dell'eliminazione. Uno snapshot creato ora non può recuperare lo stato precedente.

btrfs conserva gli snapshot come subvolume:

sudo btrfs subvolume list /

Esplora lo snapshot e copia i percorsi necessari con cp -a. È preferibile copiare singoli percorsi invece di ripristinare un intero subvolume, perché il rollback elimina anche tutto ciò che è stato scritto dopo la creazione dello snapshot.

ZFS espone ogni snapshot come directory di sola lettura:

zfs list -t snapshot
ls /tank/data/.zfs/snapshot/

La directory .zfs è nascosta e non compare in un semplice ls della root del dataset, ma puoi accedervi specificandone il nome. Copia i file da quella directory. zfs rollback ripristina l'intero dataset e elimina tutti gli snapshot più recenti di quello specificato, quindi usalo solo come ultima risorsa.

Gli snapshot LVM sono volumi copy-on-write con una dimensione fissa:

sudo lvs
sudo mount -o ro /dev/vg0/data-snap /mnt/snap

Monta lo snapshot in sola lettura e copia i file. Controlla lvs prima di considerarlo valido, perché uno snapshot LVM che esaurisce lo spazio allocato viene invalidato dal kernel; dopo l'invalidazione, il suo contenuto è perso.

Uno snapshot non è un backup. Si trova sullo stesso disco o nello stesso pool dell'originale e quindi è esposto agli stessi guasti. È molto efficace per annullare un errore commesso due minuti fa, che è esattamente il suo scopo in questo caso.

Recupero per carving con PhotoRec, su un'immagine e mai sul disco in uso

Se nessuno dei metodi precedenti è applicabile, resta il carving: si analizza il dispositivo grezzo alla ricerca dei pattern di byte che indicano l'inizio di un tipo di file noto, quindi si scrive su disco tutto ciò che segue. Il carving legge soltanto i dati dei file. I nomi dei file, la struttura delle directory, i timestamp e la proprietà sono metadati del filesystem, ed è proprio questa parte che rm ha distrutto; pertanto non è possibile recuperarli. Si ottengono file denominati f0384512.jpg in una directory di output numerata, da ordinare manualmente.

Due regole determinano se questa procedura può funzionare.

Per prima cosa, creare un'immagine del dispositivo prima di eseguire qualsiasi altra operazione su di esso. Su Debian e Ubuntu il pacchetto è gddrescue e il binario installato è 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 deve trovarsi su un dispositivo diverso, con almeno lo stesso spazio libero della capacità della partizione. lsblk -b mostra le dimensioni esatte in byte. Il file di mappa consente di riprendere una copia interrotta senza ricominciare da capo. Dopo aver creato l'immagine, è possibile provare in seguito un secondo strumento sugli stessi identici byte; non è possibile farlo se il primo strumento ha sovrascritto il disco.

In secondo luogo, indicare il file immagine allo strumento di recupero.

sudo photorec /d /mnt/rescue/recup /mnt/rescue/vdb1.img

photorec apre un menu testuale. Selezionare la partizione, quindi il tipo di filesystem, le firme dei file da cercare e infine la directory di destinazione. Prima di iniziare, limitare l'elenco delle firme ai tipi di file effettivamente persi, perché l'elenco predefinito cerca qualsiasi tipo di file e produce decine di migliaia di frammenti da esaminare.

testdisk, incluso nello stesso pacchetto, dispone di una propria funzione di undelete e supporta solo FAT, exFAT, NTFS ed ext2. Su ext4 questo lascia photorec.

I file frammentati possono essere recuperati in modo incompleto. Il carving presuppone che i blocchi di un file siano contigui; pertanto, se l'allocatore ha distribuito il file in più parti del disco, il file può essere ricomposto in modo errato oppure non essere trovato. I file multimediali vengono recuperati con risultati ragionevoli perché hanno intestazioni riconoscibili. I file di testo semplice, di configurazione e il codice sorgente vengono recuperati male, perché non esiste una firma di byte che indichi l'inizio di uno script shell.

Lo spazio indesiderato: come è stato eliminato il percorso errato

Quasi ogni incidente con rm -rf è causato dalla shell. rm riceve un elenco di percorsi e li rimuove uno alla volta. Non sa quale fosse l'intento dell'utente.

Il caso classico è un singolo spazio:

rm -rf /home/deploy/app /old
rm -rf /home/deploy/app/old

La prima riga contiene due argomenti. Elimina l'applicazione, quindi elimina /old. Se /old non esiste, rm non stampa nulla, perché -f sopprime l'errore relativo al file mancante. L'assenza di output non è una conferma.

Il secondo caso è una variabile senza virgolette che contiene uno spazio:

dir="/srv/my app"
rm -rf $dir

La shell divide il valore in corrispondenza degli spazi vuoti, quindi rm riceve /srv/my e app come due percorsi distinti. Scritto come rm -rf "$dir", è un unico percorso.

Il terzo caso è una variabile vuota, in genere perché il comando che avrebbe dovuto valorizzarla non è riuscito:

rm -rf "$TARGET"/*

Con TARGET non impostata, l'espansione produce rm -rf /*. GNU rm rifiuta la forma nuda: rm -rf / stampa rm: it is dangerous to operate recursively on '/' e si interrompe. La forma con glob non offre la stessa protezione, perché la shell sostituisce /* con un elenco di percorsi reali di primo livello prima che rm venga eseguito; / non è tra questi percorsi e quindi il controllo non viene mai attivato.

Abitudini che evitano il prossimo incidente

  • Racchiudi tra virgolette ogni variabile usata come percorso. Scrivi "$dir" ogni volta, anche all'interno di test e cicli.
  • Interrompi l'esecuzione se il valore è vuoto. rm -rf "${TARGET:?TARGET is not set}"/* arresta la shell con il messaggio specificato prima dell'avvio di rm, quando TARGET non è impostata o è vuota. Inserisci set -euo pipefail all'inizio di ogni script che elimina file.
  • Aggiungi --one-file-system. Indica a rm di ignorare le directory che si trovano su un filesystem diverso da quello dell'argomento specificato. In questo modo un'eliminazione ricorsiva non può attraversare un volume di backup montato o un bind mount.
  • Non eliminare file come root. Un account di servizio può eliminare soltanto ciò che gli appartiene. Questo è il motivo principale per eseguire ogni servizio con un proprio utente senza privilegi. Se non sai quali risorse può raggiungere un determinato account, leggere i bit dei permessi nell'output di ls fornisce la risposta con un solo comando.
  • Stampa l'elenco prima di agire. In uno script, costruisci i percorsi, applica printf '%s\n', leggi l'output, quindi esegui l'eliminazione in un secondo passaggio.
  • Tieni a portata di mano un comando per il cestino. sudo apt install trash-cli offre trash-put, trash-list, trash-restore e trash-empty. I file eliminati vengono spostati in ~/.local/share/Trash, mentre trash-empty 30 elimina tutto ciò che è più vecchio di trenta giorni.

Impostare un alias da rm a trash-put sembra il passo successivo più ovvio, ma è una trappola. L'alias crea un automatismo che non funziona sul server successivo se non è configurato, inoltre gli alias non si applicano all'interno degli script, cioè nel contesto in cui si verificano gli errori più costosi. Digita intenzionalmente trash-put.

L'unico ripristino che funziona sempre

Tutto ciò che precede è una possibilità. Un backup non lo è.

Un backup è effettivo se vengono soddisfatte due condizioni. Viene eseguito secondo una pianificazione senza che tu debba ricordartene e lo hai ripristinato almeno una volta. Un repository dal quale nessuno ha mai eseguito un ripristino è solo una convinzione, perché i problemi che possono renderlo inutilizzabile, come un percorso errato nell'elenco degli elementi inclusi o una password del repository che nessuno ha annotato, emergono soltanto quando serve.

Con restic, un ripristino richiede due comandi.

restic -r /srv/restic-repo snapshots
restic -r /srv/restic-repo restore latest --target /mnt/rescue --include /srv/appdata

Esegui il ripristino in una directory vuota invece che sul percorso in uso, così puoi confrontare i due contenuti prima di spostare qualsiasi elemento nella posizione definitiva. Configurare i backup restic su un VPS descrive la configurazione del repository e il timer systemd che esegue il backup.

Con Borg:

borg list /srv/borg-repo
borg extract /srv/borg-repo::daily-2026-08-08 srv/appdata

I percorsi all'interno di un archivio Borg vengono memorizzati senza lo slash iniziale, quindi srv/appdata trova corrispondenze e /srv/appdata non ne trova nessuna. borg extract scrive nella directory di lavoro corrente, quindi usa prima cd per una directory temporanea.

Se non hai ancora scelto tra i due strumenti, il confronto tra restic e Borg descrive la deduplicazione e i repository append-only, una caratteristica che impedisce a un server violato di eliminare la propria cronologia dei backup. Entrambi gli strumenti sono adatti. La scelta sbagliata è non eseguirne nessuno.

Un nuovo server è il momento meno costoso per configurare tutto, prima che contenga dati che valga la pena non perdere. I primi dieci minuti su un nuovo VPS è il punto in cui svolgere questa attività, insieme alla configurazione di SSH e del firewall.

Aggiungi quindi al calendario un'attività ricorrente: ogni mese ripristina una directory dal repository in /tmp e leggi i file. Questa singola abitudine vale più di tutti gli strumenti descritti in questa pagina.

FAQ

È possibile recuperare un file eliminato su ext4?

Di solito no. Quando viene rimosso l’ultimo hard link a un file, ext4 elimina dall’inode l’albero degli extent; sul disco non rimane quindi alcuna informazione sulla posizione dei dati. extundelete e ext4magic cercano nel journal di ext4 una copia precedente dell’inode. Questo è utile solo se l’eliminazione è avvenuta pochi minuti prima e il filesystem è rimasto inattivo da allora. Nessuno dei due progetti è sottoposto a manutenzione attiva. Esegui uno dei due strumenti su un dispositivo non montato o su un’immagine disco, mai su un filesystem montato, e verifica prima il dispositivo su cui stai lavorando con sudo dumpe2fs -h /dev/vdb1 | grep -i journal.

Un servizio ha ancora aperto il file eliminato. È possibile recuperarlo?

Sì, ed è il caso migliore. Finché un processo mantiene aperto il file, il relativo inode e i blocchi dati restano allocati, quindi i dati sono ancora leggibili. Non riavviare il servizio, perché la chiusura dell’ultimo descrittore completa l’eliminazione. Esegui sudo lsof +L1 per elencare i file aperti con un link count pari a 0, annota il PID e il numero del file descriptor, quindi copia il contenuto tramite /proc con sudo cp /proc/1234/fd/3 /mnt/rescue/events.log. Scrivi la copia su un filesystem diverso. Le voci che mostrano mem al posto del numero di un file descriptor sono mappate in memoria e non hanno un percorso /proc/<pid>/fd da cui copiare.

Perché creare un’immagine del disco invece di eseguire lo strumento di recupero sul disco?

Perché ogni strumento deve scrivere l’output da qualche parte, e una scrittura sul filesystem che stai recuperando può occupare i blocchi liberi che contengono ancora i tuoi dati. Copia prima la partizione su un dispositivo diverso con sudo ddrescue -n /dev/vdb1 /mnt/rescue/vdb1.img /mnt/rescue/vdb1.map, quindi indica a photorec il file immagine. L’immagine consente anche di provare in seguito un secondo strumento esattamente sugli stessi byte. Questo non è possibile dopo che una scrittura ha sovrascritto l’originale.

rm -rf / distrugge ancora un sistema Linux?

Il comando senza altri elementi non lo fa. GNU rm si rifiuta di eseguirlo e stampa rm: it is dangerous to operate recursively on '/'. Le forme pericolose sono quelle ottenute attraverso un altro percorso. rm -rf "$TARGET"/* con TARGET non impostata si espande in rm -rf /*, e la shell passa a rm un elenco di directory reali di primo livello. Nessuna di queste directory è /, quindi la protezione non scatta. Scrivi invece "${TARGET:?TARGET is not set}": la shell si interrompe prima che venga eseguito rm.

Un filesystem snapshot è un backup?

No. Uno snapshot btrfs o ZFS risiede nello stesso pool dei dati che protegge. Un disco guasto o un pool distrutto eliminano quindi entrambi. Uno snapshot LVM presenta inoltre il problema delle dimensioni fisse: quando si riempie, il kernel lo invalida e il suo contenuto va perso. Gli snapshot sono ottimi per annullare l’eliminazione avvenuta due minuti prima. Per tutto il resto, conserva un repository su hardware separato.

#linux#rm#data-recovery#backups#ext4