Як відновити файли після rm -rf на ext4
Помилково виконали rm -rf? Негайно припиніть запис на диск, розмонтуйте ext4 і перевірте доступні способи відновлення у правильному порядку.
Що робити в перші sixty секунд
Від двох дій залежить, чи вдасться відновити файли, видалені за допомогою rm -rf. Обидві дії потрібно виконати до того, як ви відкриєте пошукову систему. Припиніть запис на цю файлову систему. Потім виведіть її з використання: розмонтуйте або перемонтуйте в режимі лише для читання.
rm нічого не стирає. Команда видаляє запис каталогу, а потім позначає inode і блоки даних файлу як вільні. Байти все ще зберігаються на пристрої. Вони залишаються там, доки розподілювач блоків не передасть ці блоки іншому об’єкту, а той не перезапише їх. Кожної секунди, поки файлова система змонтована й активно використовується, daemon записує рядок у журнал або база даних скидає сторінку. Будь-який із цих записів може потрапити в блоки, які потрібно відновити.
Тому першими потрібно виконати команди, що припиняють запис, а не команди для відновлення файлів.
sudo systemctl stop nginx postgresql
sudo umount /mnt/dataЯкщо umount повертає umount: /mnt/data: target is busy., визначте, який процес утримує файлову систему відкритою.
sudo fuser -vm /mnt/data
sudo lsof +D /mnt/dataЯкщо звільнити файлову систему не вдається, перемонтуйте її в режимі лише для читання. Монтування в режимі лише для читання припиняє нові операції розподілу, а це охоплює більшість необхідних дій.
sudo mount -o remount,ro /mnt/dataЯкщо видалений шлях розташований у кореневій файловій системі, ситуація складніша. sudo mount -o remount,ro / зазвичай завершується помилкою mount: /: cannot remount /dev/vda1 read-only., оскільки запущені процеси утримують файли відкритими для запису, а kernel не примусово закриває їх. На VPS практичне рішення — rescue або recovery mode, наданий вашим провайдером. Він завантажує окрему live system із підключеним, але не змонтованим диском. Після цього кожна наведена нижче команда працює з пристроєм, на який ніхто не записує.
Для всього цього посібника діє одне правило. Ніколи не записуйте відновлені файли, образ диска або щойно встановлений інструмент у файлову систему, з якої виконується відновлення. Підключіть другий том або передайте результат на іншу машину через SSH.
Чому відновлення після rm -rf на ext4 здебільшого безнадійне
Перш ніж щось встановлювати, оцініть реальні шанси. Перевірте, з якою файловою системою ви працюєте:
lsblk -fУ ext4, яка є типовою файловою системою майже в кожному образі VPS, розташування даних файлу зберігається в його inode як дерево extent. Extent — це запис, який вказує, що логічний блок N цього файлу починається з фізичного блоку M і займає L блоків. Невеликі файли зберігають до чотирьох таких записів безпосередньо в inode. Для більших файлів inode посилається на додаткові блоки, у яких зберігається решта дерева.
Коли останнє посилання на файл видаляється, ext4 проходить це дерево, повертає кожен extent розподільнику блоків і очищає дерево в inode. Після цього inode позначається як вільний, а в ньому записується час видалення. Самі дані не змінюються. Видаляється лише запис про розташування цих даних.
У цьому полягає відмінність від ext3, де видалений inode зберігав достатньо інформації, щоб такий інструмент, як ext3grep, міг пройти за цими даними. На ext4 все ще можна вивести список видалених inode:
sudo debugfs -R lsdel /dev/vdb1debugfs відкриває пристрій у режимі лише читання, якщо не передати йому -w. Тому цю команду безпечно виконувати на відмонтованому пристрої, і спроба нічого не коштує. Inode буде знайдено й виведено. На цьому відновлення завершується: карту блоків, яку раніше містив цей inode, очищено, тому dump не має даних, за якими можна продовжити пошук.
Два інструменти намагаються обійти це обмеження, читаючи журнал. Журнал — це кільцевий буфер фіксованого розміру, який ext4 використовує для узгодження метаданих після збою. Він може містити старішу копію inode, що існувала до видалення. Обидва інструменти — extundelete і ext4magic — виконують пошук у журналі. Перевірте, з яким обсягом журналу ви працюєте:
sudo dumpe2fs -h /dev/vdb1 | grep -i journalЖурнал містить лише метадані та має невеликий розмір, тому звичайні операції запису швидко перезаписують його вміст. На робочому сервері період, протягом якого в журналі ще існує inode до видалення, вимірюється хвилинами. Жоден із цих інструментів активно не підтримується, і вони доступні не в кожному дистрибутиві. Розглядайте їх як малоймовірний спосіб відновлення. Запускайте їх на відмонтованому пристрої або образі диска й не дивуйтеся, якщо вони нічого не знайдуть.
Якщо lsblk -f повідомляє xfs, ситуація не краща, оскільки для XFS також немає підтримуваного засобу відновлення видалених файлів. Наведений нижче порядок дій цього не змінює.
Чи відкритий файл у запущеному процесі?
Це єдиний спосіб відновлення на цій сторінці з хорошими шансами на успіх. Саме тому не слід перезапускати сервіс, який використовував файл.
Файл справді зникає лише тоді, коли до нуля зменшуються два лічильники: кількість записів каталогів, що вказують на його inode, і кількість відкритих дескрипторів файлу. rm зменшує до нуля перший лічильник. Якщо процес усе ще утримує файл відкритим, другий лічильник не дорівнює нулю, тому inode і його блоки все ще виділені, а дані залишаються доступними для читання.
Знайдіть відкриті файли, кількість жорстких посилань на які зменшилася до нуля:
sudo lsof +L1+L1 означає перелічити відкриті файли, кількість жорстких посилань на які менша за 1. У кожному результаті вказано процес, номер дескриптора файлу, NLINK від 0 і шлях, що закінчується на (deleted). Візьміть PID і номер дескриптора та передайте їх до /proc:
sudo ls -l /proc/1234/fdЗапис має вигляд 3 -> /var/log/app/events.log (deleted). Це посилання все ще забезпечує доступ до даних. Скопіюйте їх до іншої файлової системи:
sudo cp /proc/1234/fd/3 /mnt/rescue/events.logВикористовуйте cp, а не mv. Відкриття /proc/1234/fd/3 створює новий дескриптор для того самого inode, починаючи зі зміщення zero, тому ви отримаєте весь файл, а не лише частину після поточної позиції запису.
Варто знати про два обмеження. Видалене дерево каталогів у такий спосіб не відновлюється, оскільки утримуються лише окремі файли, які процес мав відкритими. Файл бази даних, скопійований під час виконання запису рушієм, є копією, узгодженою зі станом після збою. Тому заплануйте запуск власного механізму відновлення рушія, а не вважайте копію коректною. Записи, для яких lsof показує mem замість номера дескриптора, є memory-mapped. Для них немає запису /proc/<pid>/fd, з якого можна виконати копіювання.
Чи є у вас snapshot у btrfs, ZFS або LVM?
Якщо файлова система підтримує snapshot, видалені файли вже зберігаються в одному з них без змін. Це допомагає лише тоді, коли snapshot існував до видалення. Усе, що ви створите зараз, не відновить попередній стан.
У btrfs snapshot зберігаються як subvolume:
sudo btrfs subvolume list /Перегляньте snapshot і скопіюйте потрібні шляхи за допомогою cp -a. Краще копіювати окремі шляхи, а не повертати весь subvolume до попереднього стану, оскільки rollback також видалить усі дані, записані після створення snapshot.
ZFS надає доступ до кожного snapshot як до каталогу лише для читання:
zfs list -t snapshot
ls /tank/data/.zfs/snapshot/Каталог .zfs прихований і не відображається у звичайному ls кореня dataset, але до нього можна перейти за іменем. Скопіюйте файли звідти. zfs rollback повертає весь dataset до вказаного стану та знищує всі snapshot, створені пізніше за вказаний. Тому використовуйте цю команду лише в крайньому разі.
Snapshot LVM — це том copy-on-write із фіксованим розміром:
sudo lvs
sudo mount -o ro /dev/vg0/data-snap /mnt/snapЗмонтуйте його лише для читання та скопіюйте потрібні дані. Перевірте lvs, перш ніж покладатися на snapshot, оскільки snapshot LVM, у якому заповнено виділений простір, ядро позначає як недійсний. Після цього його вміст втрачено.
Snapshot не є backup. Він зберігається на тому самому диску або в тому самому pool, що й оригінал, тому зазнає тих самих збоїв. Snapshot добре підходить для скасування помилки, зробленої дві хвилини тому. Саме це потрібно в цій ситуації.
Відновлення за сигнатурами за допомогою PhotoRec — лише з образу, ніколи з робочого диска
Якщо жоден із наведених вище способів не підходить, залишається відновлення за сигнатурами: сканування необробленого пристрою в пошуках послідовностей байтів, які позначають початок відомого типу файлу, з подальшим записом усіх знайдених даних. Відновлення за сигнатурами читає лише дані файлів. Імена файлів, структура каталогів, часові мітки та дані про власника належать до метаданих файлової системи. Саме ці метадані знищив rm, тому відновити їх неможливо. Ви отримаєте файли з іменами на кшталт f0384512.jpg у пронумерованому вихідному каталозі та сортуватимете їх вручну.
Чи спрацює цей спосіб взагалі, визначають два правила.
По-перше, створіть образ пристрою, перш ніж використовувати на ньому будь-які інші інструменти. У Debian і Ubuntu пакет називається gddrescue, а бінарний файл, який він встановлює, — 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 має розташовуватися на іншому пристрої, де вільного місця не менше, ніж містить розділ. lsblk -b виводить точні розміри в байтах. Файл мапи дає змогу продовжити перерване копіювання, а не починати його спочатку. Після створення образу ви зможете пізніше спробувати інший інструмент із точно такими самими байтами. Якщо ж перший інструмент записав дані поверх диска, це буде неможливо.
По-друге, вкажіть файлу образу як джерело для інструмента відновлення.
sudo photorec /d /mnt/rescue/recup /mnt/rescue/vdb1.imgphotorec відкриває текстове меню. Виберіть розділ, потім тип файлової системи, сигнатури файлів для пошуку та вихідний каталог. До початку роботи звузьте список сигнатур до фактично втрачених типів файлів. Стандартний список шукає все й передає вам для перегляду десятки тисяч фрагментів.
testdisk, що входить до того самого пакета, має власну функцію відновлення видалених файлів і підтримує лише FAT, exFAT, NTFS та ext2. Для ext4 це означає photorec.
Очікуйте, що фрагментовані файли буде відновлено пошкодженими. Відновлення за сигнатурами припускає, що блоки файлу розташовані послідовно. Тому файл, блоки якого розподілені по різних ділянках диска, буде або зібрано неправильно, або не знайдено взагалі. Медіафайли зазвичай відновлюються досить добре, оскільки мають чіткі заголовки. Звичайний текст, конфігураційні файли та вихідний код відновлюються погано, оскільки не існує байтової сигнатури, яка позначає початок shell-скрипту.
Зайвий пробіл: як було видалено неправильний шлях
Майже кожен випадок із rm -rf є проблемою оболонки. rm отримує список шляхів і видаляє їх по одному. Команда не бачить, що саме ви мали на увазі.
Класичний випадок — один пробіл:
rm -rf /home/deploy/app /old
rm -rf /home/deploy/app/oldУ першому рядку передано два аргументи. Він видаляє застосунок, а потім — /old. Якщо /old не існує, rm нічого не виводить, оскільки -f пригнічує помилку про відсутній файл. Відсутність повідомлення не підтверджує правильність команди.
Другий варіант — неекранована змінна, що містить пробіл:
dir="/srv/my app"
rm -rf $dirОболонка розділяє значення за пробільними символами, тому rm отримує /srv/my і app як два окремі шляхи. У записі rm -rf "$dir" це один шлях.
Третій варіант — порожня змінна. Зазвичай це відбувається через помилку команди, яка мала надати їй значення:
rm -rf "$TARGET"/*Якщо TARGET не задано, цей вираз розгортається в rm -rf /*. GNU rm відхиляє форму без аргументів: rm -rf / виводить rm: it is dangerous to operate recursively on '/' і завершує роботу. Для форми з glob такого захисту немає, оскільки оболонка замінює /* списком фактичних шляхів верхнього рівня ще до запуску rm, а / не входить до цього списку, тому перевірка не спрацьовує.
Звички, які запобігають наступній помилці
- Беріть у лапки кожну змінну, яку використовуєте як шлях. Пишіть
"$dir"щоразу, зокрема всередині умов і циклів. - Завершуйте роботу, якщо значення порожнє.
rm -rf "${TARGET:?TARGET is not set}"/*зупиняє shell із вашим повідомленням до запускуrm, якщоTARGETне задана або порожня. Додавайтеset -euo pipefailна початку будь-якого скрипту, який видаляє файли. - Додавайте
--one-file-system. Ця опція вказуєrmпропускати каталоги, розташовані в іншій файловій системі, ніж аргумент команди. Це не дає рекурсивному видаленню перейти у змонтований том із резервними копіями або bind mount. - Не видаляйте файли від імені root. Сервісний обліковий запис може видалити лише те, чим він володіє. Саме на цьому ґрунтується запуск кожного сервісу від імені власного непривілейованого користувача. Якщо ви не впевнені, до яких файлів має доступ певний обліковий запис, перевірка бітів доступу у виведенні ls дасть відповідь однією командою.
- Виводьте список до початку операції. У скрипті сформуйте шляхи, виконайте для них
printf '%s\n', перегляньте виведення, а потім видаліть їх під час другого проходу. - Тримайте команду для переміщення файлів у кошик під рукою.
sudo apt install trash-cliнадає вамtrash-put,trash-list,trash-restoreіtrash-empty. Видалені файли переміщуються до~/.local/share/Trash, аtrash-empty 30очищає все, що старше за тридцять днів.
Створити alias для rm як trash-put здається очевидним наступним кроком, але це пастка. Такий alias формує рефлекс, який не спрацює на іншому сервері без нього. Крім того, alias не діють усередині скриптів, а саме там трапляються найдорожчі помилки. Натомість навмисно вводьте trash-put.
Єдине відновлення, яке працює щоразу
Усе описане вище — лише можливість. Резервна копія — ні.
Резервна копія є справжньою лише за двох умов. Вона запускається за розкладом без нагадування з вашого боку, і ви хоча б раз відновлювали з неї дані. Репозиторій, з якого ще ніхто нічого не відновлював, ґрунтується лише на припущенні, оскільки причини, через які резервна копія стає непридатною (неправильний шлях у списку include або пароль до репозиторію, який ніхто не записав), виявляються лише тоді, коли вона потрібна.
У restic відновлення виконується двома командами.
restic -r /srv/restic-repo snapshots
restic -r /srv/restic-repo restore latest --target /mnt/rescue --include /srv/appdataВідновлюйте дані в порожній каталог, а не поверх робочого шляху. Так ви зможете порівняти обидві версії, перш ніж переміщувати дані на потрібне місце. У розділі Налаштування резервного копіювання restic на VPS описано налаштування репозиторію та таймер systemd, який запускає резервне копіювання.
Для Borg:
borg list /srv/borg-repo
borg extract /srv/borg-repo::daily-2026-08-08 srv/appdataШляхи всередині архіву Borg зберігаються без початкового слеша, тому srv/appdata знаходить збіги, а /srv/appdata не знаходить нічого. borg extract записує дані в поточний робочий каталог, тому спочатку виконайте cd до тимчасового каталогу.
Якщо ви ще не вибрали між ними, у розділі Порівняння restic і Borg описано дедуплікацію та репозиторії append-only. Саме ця властивість не дає breached-серверу видалити власну історію резервного копіювання. Підійде будь-який із цих інструментів. Неправильний варіант — не запускати жоден із них.
Новий сервер — найкращий момент для налаштування резервного копіювання, поки на ньому ще немає даних, які шкода втратити. У розділі Перші десять хвилин на новому VPS описано, де виконати цю роботу разом із налаштуванням SSH і firewall.
Після цього додайте до календаря регулярне нагадування: щомісяця відновлюйте один каталог із репозиторію в /tmp і перевіряйте файли. Ця проста звичка важливіша за всі інструменти на цій сторінці.
FAQ
Чи можна відновити видалений файл в ext4?
Зазвичай ні. Коли останнє посилання на файл видаляється, ext4 очищає дерево extent із inode, тому на диску більше не залишається інформації про розташування даних. extundelete і ext4magic шукають старішу копію цього inode у журналі ext4. Це допомагає лише тоді, коли видалення відбулося кілька хвилин тому, а файлова система відтоді не використовувалася. Жоден із цих проєктів активно не супроводжується. Запускайте будь-який із них для відмонтованого пристрою або образу диска, але ніколи не для змонтованої файлової системи. Спочатку перевірте, з чим ви працюєте, за допомогою sudo dumpe2fs -h /dev/vdb1 | grep -i journal.
Сервіс досі тримає видалений файл відкритим. Чи можна його відновити?
Так, це найкращий випадок. Поки процес утримує файл відкритим, його inode і блоки даних залишаються виділеними, тому дані все ще можна прочитати. Не перезапускайте сервіс, оскільки закриття останнього дескриптора остаточно завершує видалення. Виконайте sudo lsof +L1, щоб перелічити відкриті файли з кількістю посилань 0. Запишіть PID і номер файлового дескриптора, а потім скопіюйте файл через /proc за допомогою sudo cp /proc/1234/fd/3 /mnt/rescue/events.log. Записуйте копію в іншу файлову систему. Записи, у яких замість номера дескриптора показано mem, є memory-mapped і не мають шляху /proc/<pid>/fd, з якого їх можна скопіювати.
Чому слід створити образ диска, а не запускати засіб відновлення безпосередньо на ньому?
Тому що кожен засіб має кудись записувати результати, а запис у файлову систему, яку ви відновлюєте, може потрапити у вільні блоки, де все ще зберігаються ваші дані. Спочатку скопіюйте розділ на інший пристрій за допомогою sudo ddrescue -n /dev/vdb1 /mnt/rescue/vdb1.img /mnt/rescue/vdb1.map, а потім передайте файл образу в photorec. Образ також дає змогу пізніше спробувати інший засіб на точно такому самому наборі байтів. Після перезапису оригіналу це вже неможливо.
Чи досі rm -rf / знищує систему Linux?
Самостійно виконана команда цього не робить. GNU rm відмовляється її виконувати та виводить rm: it is dangerous to operate recursively on '/'. Небезпечними є варіанти, які надходять іншим шляхом. rm -rf "$TARGET"/* із невстановленою змінною TARGET розгортається в rm -rf /*, і оболонка передає rm список реальних каталогів верхнього рівня. Серед них немає /, тому захист не спрацьовує. Натомість напишіть "${TARGET:?TARGET is not set}", і оболонка зупиниться до запуску rm.
Чи є знімок файлової системи резервною копією?
Ні. Знімок btrfs або ZFS зберігається в тому самому пулі, що й дані, які він захищає. Тому відмова диска або знищення пулу призведе до втрати і даних, і знімка. Знімок LVM має додаткову проблему — фіксований розмір. Коли він заповнюється, ядро робить його недійсним, і його вміст втрачається. Знімки чудово підходять для скасування видалення, яке відбулося дві хвилини тому. Для всіх інших випадків зберігайте репозиторій на окремому обладнанні.