SSD Nodes Learn 🎉 VPS desde $5.50/mês
Guias Matt ConnorPor Matt Connor

Como recuperar arquivos apagados com rm -rf no ext4

Executou rm -rf no caminho errado? Pare as escritas e desmonte o disco. Veja a ordem real das opções de recuperação no ext4 antes de sobrescrever os dados.

O que fazer nos primeiros sixty seconds

Duas coisas determinam se consegue recuperar ficheiros eliminados com rm -rf, e ambas acontecem antes de abrir um motor de pesquisa. Pare de escrever nesse sistema de ficheiros. Depois retire-o de utilização, desmontando-o ou voltando a montá-lo como apenas de leitura.

rm não apaga nada. Remove a entrada do diretório e marca o inode e os blocos de dados do ficheiro como livres. Os bytes continuam no dispositivo. Permanecem lá até o alocador de blocos atribuir esses blocos a outra coisa e essa outra coisa os substituir. A cada segundo que o sistema de ficheiros continua montado e ocupado, um daemon escreve uma linha no log ou uma base de dados descarrega uma página, e qualquer uma dessas escritas pode atingir os blocos que pretende recuperar.

Por isso, os primeiros comandos devem parar as escritas, não recuperar ficheiros.

sudo systemctl stop nginx postgresql
sudo umount /mnt/data

Se umount responder umount: /mnt/data: target is busy., descubra o que mantém o sistema de ficheiros aberto.

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

Se não conseguir libertá-lo, volte a montá-lo como apenas de leitura. Uma montagem apenas de leitura impede novas alocações, que é a maior parte do que precisa.

sudo mount -o remount,ro /mnt/data

Se o caminho eliminado estava no sistema de ficheiros raiz, isto é mais difícil. sudo mount -o remount,ro / normalmente falha com mount: /: cannot remount /dev/vda1 read-only., porque os processos em execução mantêm ficheiros abertos para escrita e o kernel não os fecha à força. Num VPS, a resposta prática é o modo de rescue ou recovery do fornecedor: arranca um sistema live separado com o seu disco ligado, mas não montado. Todos os comandos abaixo são então executados contra um dispositivo no qual ninguém está a escrever.

Aplica-se uma regra a todo este guia. Nunca escreva ficheiros recuperados, uma imagem de disco ou uma ferramenta instalada recentemente no sistema de ficheiros do qual está a recuperar dados. Ligue um segundo volume ou envie a saída para outra máquina através de SSH.

Por que a recuperação com rm -rf no ext4 é, na maioria dos casos, inviável

Defina expectativas realistas antes de instalar qualquer ferramenta. Confirme qual é o sistema de ficheiros utilizado:

lsblk -f

No ext4, o sistema predefinido em praticamente todas as imagens de VPS, a localização dos dados de um ficheiro fica no seu inode, sob a forma de uma árvore de extents. Um extent é um registo que indica que o bloco lógico N desse ficheiro começa no bloco físico M e ocupa L blocos. Os ficheiros pequenos mantêm até quatro desses registos no próprio inode. Os ficheiros maiores apontam para blocos adicionais que contêm o restante da árvore.

Quando a última ligação para um ficheiro desaparece, o ext4 percorre essa árvore, devolve todos os extents ao alocador de blocos e limpa a árvore do inode. O inode é então marcado como livre e recebe um timestamp de eliminação. Os dados em si não são alterados. O único registo da localização desses dados foi apagado.

Esta é a diferença em relação ao ext3, em que um inode eliminado mantinha informação suficiente para uma ferramenta como ext3grep o seguir. Ainda pode listar inodes eliminados no ext4:

sudo debugfs -R lsdel /dev/vdb1

debugfs abre o dispositivo em modo somente leitura, exceto se passar -w, por isso esta operação é segura num dispositivo desmontado e não custa nada tentar. Os inodes serão listados. A extração de um deles é onde o processo termina, porque o mapa de blocos que esse inode mantinha foi limpo e, por isso, dump não tem nada para seguir.

Duas ferramentas tentam contornar este problema lendo o journal. O journal é um anel de tamanho fixo que o ext4 utiliza para manter os metadados consistentes depois de uma falha, e ainda pode conter uma cópia anterior do inode, criada antes da eliminação. extundelete e ext4magic procuram ambas no journal. Verifique o tamanho disponível:

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

O journal contém apenas metadados e é pequeno, por isso a atividade normal de escrita percorre-o rapidamente. Num servidor em funcionamento, a janela durante a qual o inode anterior à eliminação ainda existe é medida em minutos. Nenhuma das ferramentas é mantida ativamente e nenhuma está disponível em todas as distribuições. Considere ambas uma tentativa remota, execute-as contra um dispositivo desmontado ou uma imagem de disco e não se surpreenda se não devolverem resultados.

Se lsblk -f indicar xfs, a situação não é melhor, porque também não existe uma ferramenta de undelete suportada para XFS. A ordem das opções abaixo não se altera.

O ficheiro ainda está aberto num processo em execução?

Este é o único método de recuperação nesta página com boas probabilidades de sucesso. É também a razão pela qual não deve reiniciar o serviço que estava a utilizar o ficheiro.

Um ficheiro só desaparece realmente quando duas contagens chegam a zero: o número de entradas de diretório que apontam para o seu inode e o número de descritores de ficheiro abertos. rm faz a primeira contagem chegar a zero. Se um processo ainda mantiver o ficheiro aberto, a segunda contagem não é zero. Por isso, o inode e os seus blocos continuam alocados e os dados continuam legíveis.

Encontre ficheiros abertos cujo número de ligações caiu para zero:

sudo lsof +L1

+L1 significa listar ficheiros abertos com um número de ligações inferior a 1. Cada resultado mostra o processo, o número do descritor de ficheiro, um NLINK de 0 e um caminho terminado em (deleted). Use o PID e o número do descritor com /proc:

sudo ls -l /proc/1234/fd

Uma entrada tem o aspeto de 3 -> /var/log/app/events.log (deleted). Essa ligação ainda permite aceder aos dados. Copie-os para um sistema de ficheiros diferente:

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

Use cp, não mv. Abrir /proc/1234/fd/3 fornece um novo handle para o mesmo inode, começando no offset zero. Assim, obtém o ficheiro completo, em vez da parte posterior à posição atual do processo que o estava a escrever.

Há dois limites que deve conhecer. Uma árvore de diretórios eliminada não pode ser recuperada desta forma, porque apenas os ficheiros individuais que um processo tinha abertos continuam retidos. Além disso, um ficheiro de base de dados copiado enquanto o motor está a escrever é uma cópia consistente com uma falha. Planeie executar a recuperação própria do motor sobre essa cópia, em vez de a tratar como limpa. As entradas que lsof apresenta com mem no lugar do número do descritor estão mapeadas em memória. Essas entradas não têm uma entrada /proc/<pid>/fd a partir da qual seja possível copiar.

Tem um snapshot em btrfs, ZFS ou LVM?

Se o sistema de ficheiros suportar snapshots, os ficheiros eliminados já estão dentro de um deles, sem alterações. Isto só ajuda se existisse um snapshot antes da eliminação. Nada que crie agora consegue recuperar o estado anterior.

O btrfs mantém os snapshots como subvolumes:

sudo btrfs subvolume list /

Explore o snapshot e copie os caminhos necessários com cp -a. Prefira copiar caminhos individuais em vez de reverter um subvolume inteiro, porque uma reversão também descarta tudo o que foi escrito desde a criação do snapshot.

O ZFS expõe cada snapshot como um diretório só de leitura:

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

O diretório .zfs está oculto e não aparece num ls simples da raiz do dataset, mas pode aceder-lhe pelo nome. Copie os ficheiros a partir daí. zfs rollback reverte todo o dataset e destrói todos os snapshots mais recentes do que o snapshot indicado, por isso use-o apenas como último recurso.

Os snapshots de LVM são volumes copy-on-write com um tamanho fixo:

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

Monte-o como só de leitura e copie os ficheiros necessários. Verifique lvs antes de confiar nele, porque um snapshot de LVM que preencha o espaço alocado é invalidado pelo kernel. Depois disso, o seu conteúdo desaparece.

Um snapshot não é uma cópia de segurança. Fica no mesmo disco ou no mesmo pool que o original e, por isso, partilha todas as falhas do original. É muito eficaz para desfazer um erro cometido há dois minutos, que é exatamente o objetivo neste caso.

Recuperação com PhotoRec, sempre numa imagem e nunca no disco em uso

Se nada do que foi descrito acima se aplicar, resta a recuperação por assinaturas: analisar o dispositivo bruto à procura de padrões de bytes que indiquem o início de um tipo de ficheiro conhecido e gravar tudo o que surgir a seguir. Este método lê apenas os dados dos ficheiros. Os nomes, a estrutura de diretórios, os timestamps e a propriedade pertencem aos metadados do sistema de ficheiros. Foi precisamente essa informação que rm destruiu, por isso nada disso é recuperado. Obtém ficheiros com nomes como f0384512.jpg num diretório de saída numerado e tem de os organizar manualmente.

Duas regras determinam se este método pode funcionar.

Primeiro, crie uma imagem do dispositivo antes de executar qualquer outra operação sobre ele. No Debian e no Ubuntu, o pacote é gddrescue e o binário instalado por esse pacote é 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 tem de estar num dispositivo diferente, com pelo menos tanto espaço livre quanto o tamanho da partição. lsblk -b apresenta os tamanhos exatos em bytes. O ficheiro de mapa permite retomar uma cópia interrompida sem começar de novo. Depois de criar a imagem, pode testar mais tarde uma segunda ferramenta sobre exatamente os mesmos bytes. Isso não é possível se a primeira ferramenta tiver gravado por cima do disco.

Segundo, indique o ficheiro de imagem à ferramenta de recuperação.

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

photorec abre um menu de texto. Escolha a partição, depois o tipo de sistema de ficheiros, em seguida as assinaturas de ficheiros a procurar e, por fim, o diretório de destino. Antes de começar, limite a lista de assinaturas aos tipos de ficheiro que perdeu. A lista predefinida procura todos os tipos e pode produzir dezenas de milhares de fragmentos para analisar.

testdisk, do mesmo pacote, tem a sua própria função de recuperação de ficheiros eliminados e suporta apenas FAT, exFAT, NTFS e ext2. Em ext4, isso deixa photorec.

É normal que os ficheiros fragmentados sejam recuperados com erros. A recuperação por assinaturas assume que os blocos de um ficheiro são contíguos. Por isso, um ficheiro que o alocador dividiu pelo disco pode ser remontado incorretamente ou não ser encontrado. Os ficheiros multimédia costumam ser recuperados razoavelmente bem porque têm cabeçalhos distintos. Ficheiros de texto simples, configuração e código-fonte são recuperados com dificuldade, porque não existe uma assinatura de bytes que marque o início de um shell script.

O espaço solto: como o caminho errado foi eliminado

Quase todos os acidentes com rm -rf são problemas da shell. rm recebe uma lista de caminhos e remove cada um deles pela ordem. Nunca sabe o que pretendia fazer.

O caso clássico é um único espaço:

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

A primeira linha contém dois argumentos. Elimina a aplicação e depois elimina /old. Se /old não existir, rm não apresenta absolutamente nada, porque -f suprime o erro de ficheiro inexistente. O silêncio não é confirmação.

O segundo caso é uma variável sem aspas que contém um espaço:

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

A shell divide o valor nos espaços em branco, por isso rm recebe /srv/my e app como dois caminhos separados. Escrito como rm -rf "$dir", é um único caminho.

O terceiro caso é uma variável vazia, normalmente porque o comando que deveria preenchê-la falhou:

rm -rf "$TARGET"/*

Com TARGET definida como vazia, isto expande para rm -rf /*. O GNU rm recusa a forma simples: rm -rf / apresenta rm: it is dangerous to operate recursively on '/' e para. A forma com glob não tem a mesma proteção, porque a shell substitui /* por uma lista de caminhos reais de nível superior antes de rm ser executado. / não faz parte dessa lista, por isso a proteção nunca é acionada.

Hábitos que evitam o próximo incidente

  • Coloque entre aspas todas as variáveis usadas como caminhos. Escreva "$dir" sempre, inclusive dentro de testes e loops.
  • Pare quando o valor estiver vazio. rm -rf "${TARGET:?TARGET is not set}"/* faz o shell parar com a sua mensagem antes de rm ser executado, sempre que TARGET não estiver definido ou estiver vazio. Coloque set -euo pipefail no início de qualquer script que elimine ficheiros.
  • Adicione --one-file-system. Isto faz rm ignorar qualquer diretório que esteja num sistema de ficheiros diferente daquele indicado no argumento. Assim, uma eliminação recursiva não pode entrar num volume de backup montado nem num bind mount.
  • Não elimine ficheiros como root. Uma conta de serviço só pode eliminar o que lhe pertence. Esse é o principal motivo para executar cada serviço com o seu próprio utilizador sem privilégios. Se não souber a que recursos uma determinada conta pode aceder, ler os bits de permissões numa listagem de ls dá a resposta com um único comando.
  • Mostre a lista antes de agir sobre ela. Num script, construa os caminhos, aplique printf '%s\n', leia o resultado e elimine os ficheiros numa segunda passagem.
  • Mantenha um comando de reciclagem disponível. sudo apt install trash-cli fornece trash-put, trash-list, trash-restore e trash-empty. Os ficheiros eliminados são movidos para ~/.local/share/Trash, e trash-empty 30 elimina tudo o que tiver mais de trinta dias.

Criar um alias de rm para trash-put parece o passo seguinte óbvio, mas é uma armadilha. O alias cria um reflexo que falha no servidor seguinte, caso este não o tenha, e os aliases não se aplicam dentro de scripts, que é onde ocorrem os erros mais dispendiosos. Escreva trash-put deliberadamente.

A única recuperação que funciona sempre

Tudo o que foi apresentado até aqui é uma possibilidade. Um backup não é uma possibilidade.

Duas coisas tornam um backup real. Ele é executado de acordo com um agendamento sem depender da sua memória, e você já o restaurou pelo menos uma vez. Um repositório do qual ninguém nunca restaurou nada é uma crença, porque os problemas que o tornam inútil — um caminho incorreto na lista de inclusão ou uma palavra-passe do repositório que ninguém registou — só aparecem no dia em que é necessário utilizá-lo.

Com o restic, uma restauração requer dois comandos.

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

Restaure para um diretório vazio, em vez de substituir o caminho em produção. Assim, pode comparar os dois antes de colocar qualquer ficheiro no local correto. Configurar backups do restic num VPS explica como configurar o repositório e o temporizador do systemd que executa o backup.

Com o Borg:

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

Os caminhos dentro de um arquivo Borg são armazenados sem a barra inicial. Por isso, srv/appdata encontra correspondências e /srv/appdata não encontra nenhuma. borg extract escreve no diretório de trabalho atual. Por isso, execute cd primeiro para um diretório temporário.

Se ainda não escolheu entre os dois, a comparação entre restic e Borg explica a deduplicação e os repositórios append-only. Esta propriedade impede um servidor comprometido de eliminar o próprio histórico de backups. Qualquer uma das ferramentas serve. A resposta errada é não executar nenhuma.

Um servidor novo é o momento mais barato para configurar isto, antes de haver nele algo que valha a pena perder. Os primeiros dez minutos num VPS novo é o local adequado para esse trabalho, juntamente com a configuração do SSH e da firewall.

Depois, crie uma entrada recorrente no calendário: restaure um diretório do repositório para /tmp todos os meses e leia os ficheiros. Esse único hábito vale mais do que todas as ferramentas desta página.

FAQ

Posso recuperar um ficheiro eliminado em ext4?

Normalmente, não. Quando a última ligação para um ficheiro desaparece, o ext4 limpa a árvore de extents do inode. Assim, nada no disco regista onde os dados estavam. extundelete e ext4magic procuram no journal do ext4 uma cópia mais antiga desse inode. Isto só ajuda se a eliminação tiver ocorrido há poucos minutos e o sistema de ficheiros tiver permanecido sem atividade desde então. Nenhum dos dois projetos é mantido ativamente. Execute qualquer um deles num dispositivo desmontado ou numa imagem de disco, nunca num sistema de ficheiros montado, e confirme primeiro aquilo em que está a trabalhar com sudo dumpe2fs -h /dev/vdb1 | grep -i journal.

Um serviço ainda tem o ficheiro eliminado aberto. Posso recuperá-lo?

Sim. Este é o melhor cenário. Enquanto um processo mantiver o ficheiro aberto, o inode e os blocos de dados continuam alocados. Por isso, os dados ainda podem ser lidos. Não reinicie o serviço, porque fechar o último descritor conclui a eliminação. Execute sudo lsof +L1 para listar ficheiros abertos com uma contagem de ligações igual a 0. Registe o PID e o número do descritor de ficheiro. Depois, copie através de /proc com sudo cp /proc/1234/fd/3 /mnt/rescue/events.log. Escreva a cópia noutro sistema de ficheiros. As entradas apresentadas com mem em vez de um número de descritor estão mapeadas em memória e não têm um caminho /proc/<pid>/fd de onde possam ser copiadas.

Porque devo criar uma imagem do disco em vez de executar a ferramenta de recuperação no próprio disco?

Porque todas as ferramentas têm de escrever o resultado nalgum local. Uma escrita no sistema de ficheiros que está a recuperar pode atingir os blocos livres que ainda contêm os seus dados. Primeiro, copie a partição para outro dispositivo com sudo ddrescue -n /dev/vdb1 /mnt/rescue/vdb1.img /mnt/rescue/vdb1.map. Depois, indique o ficheiro de imagem a photorec. A imagem também permite tentar mais tarde uma segunda ferramenta exatamente sobre os mesmos bytes. Isto é impossível depois de algo ter sobrescrito o original.

rm -rf / ainda destrói um sistema Linux?

O comando isolado não o faz. O GNU rm recusa-o e apresenta rm: it is dangerous to operate recursively on '/'. As formas perigosas são as que surgem por outra via. rm -rf "$TARGET"/* com TARGET não definido expande-se para rm -rf /*. O shell entrega então a rm uma lista de diretórios de topo reais, nenhum dos quais é /. Por isso, a proteção nunca é acionada. Escreva "${TARGET:?TARGET is not set}" em vez disso. O shell para antes de rm ser executado.

Um snapshot do sistema de ficheiros é uma cópia de segurança?

Não. Um snapshot de btrfs ou ZFS fica no mesmo pool que os dados que protege. Por isso, uma falha do disco ou a destruição do pool afeta ambos ao mesmo tempo. Um snapshot de LVM tem ainda o problema de um tamanho fixo. Quando fica cheio, o kernel invalida-o e o seu conteúdo desaparece. Os snapshots são excelentes para desfazer uma eliminação ocorrida há dois minutos. Para tudo o resto, mantenha um repositório em hardware separado.

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