ServerAID
Найти гайд, команду, тег… ⌘ K
Shell и скрипты

Как удалить файл или каталог в Linux через терминал: rm, rmdir и безопасные привычки

Разбираем удаление в терминале: rm для файлов, rmdir для пустых каталогов, rm -r для каталогов с содержимым. Отдельно — чем опасен rm -rf, как удалить файл со странным именем, почему после удаления не освободилось место и как настроить автоочистку старых логов.

В Linux нет корзины: удалённое из терминала не восстанавливается штатными средствами. Поэтому важно не просто знать команду, а понимать, что именно она снесёт. Разбираем rm и rmdir, их флаги, приёмы безопасного удаления и решение проблемы «файл удалил, а место не появилось».

Удаляем файл

rm report.txt

Никакого подтверждения и никакого вывода — файл просто исчезает. Несколько файлов сразу:

rm access.log error.log debug.log

Спрашивать подтверждение перед каждым файлом:

rm -i report.txt
# rm: remove regular file 'report.txt'? y

Игнорировать несуществующие файлы и не спрашивать вообще:

rm -f temp.txt

Флаг -f (force) полезен в скриптах: команда не упадёт с ошибкой, если файла уже нет. В интерактивной работе он же делает rm максимально молчаливым, поэтому набирать его по привычке — плохая идея.

Удаляем каталог

Здесь два инструмента, и разница между ними принципиальна.

rmdir удаляет только пустой каталог:

rmdir old_project

Если внутри что-то есть, команда откажется: Directory not empty. Это не ограничение, а страховка — вы точно не потеряете данные.

rm -r удаляет каталог вместе со всем содержимым, рекурсивно:

rm -r old_project

Именно эта команда нужна, когда спрашивают, как удалить директорию в Linux через терминал: в каталоге почти всегда что-то лежит.

Полезный флаг rmdir -p — удалить каталог вместе с опустевшими родительскими:

rmdir -p project/build/tmp

Если после удаления tmp каталог build останется пустым, он тоже удалится, и так вверх по цепочке до первого непустого.

С подтверждением на каждый объект:

rm -ri old_project

Разумный компромисс — -I (заглавная): один вопрос на всю операцию, если файлов больше трёх:

rm -rI old_project

Это заметно удобнее, чем отвечать y сто раз, и всё же оставляет момент, когда можно остановиться.

rm -rf: чем именно опасен

Комбинация означает «рекурсивно, принудительно, без вопросов». Работает мгновенно и без подтверждений. Три классических способа потерять данные:

Пробел не там. Пробел разделяет аргументы, поэтому команда читается не так, как задумано:

rm -rf /home/user /old-backups    # два аргумента: снесёт весь /home/user
rm -rf /home/user/old-backups     # то, что имелось в виду

Пустая переменная. В скрипте это приводит к катастрофе:

rm -rf "$BACKUP_DIR"/*   # если переменная пуста, получится rm -rf /*

Защита — проверка перед удалением или строгий режим:

set -u                              # обращение к неустановленной переменной = ошибка
[ -n "$BACKUP_DIR" ] || exit 1      # явная проверка
rm -rf "${BACKUP_DIR:?переменная не задана}"/*

Конструкция ${VAR:?текст} прерывает выполнение с сообщением, если переменная пуста или не задана. Для скриптов удаления это самая дешёвая страховка. Про строгий режим и проверки — в статье про условия if/else в bash.

Незакрытая кавычка или неверная маска. Раскрытие * делает шелл, а не rm — команда получает уже готовый список. Поэтому проверяйте, что раскроется, до удаления:

ls *.log        # смотрим список
echo rm *.log   # видим точную команду
rm *.log        # выполняем

Современный rm отказывается удалять корень (--preserve-root включён по умолчанию), но это защищает только от буквального rm -rf /, а не от rm -rf /home или rm -rf /*.

Удаляем по маске и по условию

Все .tmp в текущем каталоге:

rm *.tmp

Рекурсивно по всему дереву — уже задача для find:

find /var/tmp -type f -name "*.tmp" -delete

Разбор по частям: -type f — только файлы (каталоги не тронет), -name "*.tmp" — маска имени, -delete — действие. Кавычки вокруг маски обязательны, иначе её раскроет шелл ещё до запуска find.

Хорошая привычка — сначала посмотреть список, потом добавить -delete:

find /var/tmp -type f -name "*.tmp"           # что найдётся
find /var/tmp -type f -name "*.tmp" -delete   # удаляем

Файлы старше 30 дней — типовая задача для очистки логов и бэкапов:

find /var/backups -type f -mtime +30 -delete

Пустые каталоги после чистки:

find /var/tmp -type d -empty -delete

Файлы больше гигабайта:

find /var/log -type f -size +1G

Полный разбор поиска, включая -exec и логические операторы, — в руководстве по find. Регулярную очистку удобно повесить задачей cron.

Файлы со странными именами

Имя начинается с дефиса. rm принимает его за флаг:

rm -file.txt              # invalid option
rm -- -file.txt           # всё после -- считается именами
rm ./-file.txt            # либо через явный путь

Пробелы в имени — кавычки или экранирование:

rm "мой файл.txt"
rm мой\ файл.txt

Совсем нечитаемое имя — удаляем по номеру inode. Сначала узнаём номер:

ls -li
# 1573248 -rw-r--r-- 1 user user 0 авг 12 10:00 ?????
find . -maxdepth 1 -inum 1573248 -delete

Имя неизвестно, но каталог мешает — интерактивно перебрать содержимое:

rm -i ./*

Место не освободилось после удаления

Частая ситуация на сервере: удалили гигабайтный лог, а df -h показывает тот же занятый объём. Причина в том, что файл всё ещё открыт процессом. В Linux данные освобождаются, когда исчезает и последняя ссылка из файловой системы, и последний открытый дескриптор.

Найти такие файлы:

sudo lsof +L1

Колонка NLINK со значением 0 означает: файл удалён, но процесс его держит. Решения два — перезапустить сервис:

sudo systemctl restart myapp

или, если перезапуск нежелателен, обнулить файл через дескриптор в /proc:

sudo truncate -s 0 /proc/<PID>/fd/<N>

Отсюда практический вывод: распухший лог правильнее обнулять (> /var/log/app.log), а не удалять — тогда место освобождается сразу и приложение продолжает писать в тот же файл. Проверить, куда ушло место, помогают du -sh * и df -h, а обзор дисков даёт lsblk.

Корзина в терминале

Если хочется обратимости, ставится trash-cli — файлы уезжают в стандартную корзину рабочего стола, а не исчезают:

sudo apt install trash-cli

trash-put report.txt      # переместить в корзину
trash-list                # посмотреть содержимое
trash-restore             # восстановить
trash-empty 30            # очистить старше 30 дней

Соблазнительно сделать alias rm='trash-put', но это опасная привычка: на чужом сервере, где алиаса нет, рука выполнит настоящий rm. Лучше приучить себя к отдельной команде trash-put.

Гарантированное затирание

Обычное удаление не стирает данные — освобождаются лишь блоки, а содержимое остаётся на диске до перезаписи. Для файла с секретами этого мало:

shred -u -z -n 3 secrets.txt

Здесь -n 3 — три прохода перезаписи, -z — финальный проход нулями, -u — удалить файл после затирания.

Важное ограничение: на SSD, а также на файловых системах с копированием при записи (btrfs, ZFS) и на любых журналируемых ФС гарантии нет — контроллер или файловая система могут писать в другие блоки. Надёжный вариант для таких носителей — полное шифрование диска, тогда достаточно уничтожить ключ. Про снапшоты, которые тоже сохраняют «удалённые» данные, — в статье про btrfs.

Права: почему файл не удаляется

Право на удаление файла определяется правами на каталог, а не на сам файл. Достаточно иметь w и x на каталоге — даже если файл принадлежит другому пользователю и открыт только на чтение.

ls -ld /var/www/uploads     # права на каталог
ls -l  /var/www/uploads/a   # права на файл

Отсюда два типичных случая:

Permission denied — нет прав на запись в каталог. Нужен sudo или смена прав, см. chmod и chown.

Operation not permitted при наличии прав — на файле стоит атрибут неизменяемости:

lsattr secrets.conf          # ----i--------- 
sudo chattr -i secrets.conf  # снять
rm secrets.conf

Отдельный случай — /tmp: там установлен sticky bit (drwxrwxrwt), поэтому удалять файлы может только их владелец, хотя писать в каталог могут все.

Частые вопросы

Как удалить непустой каталог в Linux?

Командой rm -r имя_каталога — она удаляет каталог вместе со всем содержимым. rmdir для этого не подходит: он работает только с пустыми каталогами и вернёт Directory not empty.

Если хочется контроля, используйте rm -rI — команда задаст один вопрос перед удалением, когда объектов больше трёх.

Чем rmdir отличается от rm -r?

rmdir удаляет только пустой каталог и отказывается работать, если внутри что-то есть. rm -r удаляет рекурсивно всё содержимое без вопросов.

rmdir удобен именно как страховка: если команда прошла, вы точно ничего не потеряли. Для гарантированной очистки дерева нужен rm -r.

Как удалить файл, имя которого начинается с дефиса?

Через двойной дефис — rm -- -file.txt — или через явный путь rm ./-file.txt. Без этого rm попытается разобрать имя как набор флагов и вернёт ошибку.

Правило работает и для других команд: -- означает «дальше аргументы, а не опции».

Почему после удаления файла не освободилось место на диске?

Файл удалён из каталога, но его продолжает держать открытым какой-то процесс, и ядро не освобождает блоки до закрытия дескриптора. Найти виновника: sudo lsof +L1.

Помогает перезапуск процесса. Чтобы ситуация не повторялась, распухшие логи обнуляйте (> file.log), а не удаляйте, — либо настройте logrotate.

Можно ли восстановить файл после rm?

Штатными средствами — нет, корзины в терминале не существует. Шансы есть только при немедленных действиях: размонтировать раздел и пробовать extundelete или testdisk, пока блоки не перезаписаны. На активно работающем сервере это почти безнадёжно.

Практический вывод — заранее: регулярные бэкапы, trash-cli для ручной работы и -I вместо -f в повседневных командах.

Что запомнить

  • rm файл — файл, rmdir каталог — только пустой каталог, rm -r каталог — каталог с содержимым.
  • rm -rf не задаёт вопросов и не имеет отмены: перед запуском проверяйте команду через ls или echo.
  • В скриптах защищайте переменные: set -u и ${VAR:?} не дадут rm -rf "$DIR"/* превратиться в rm -rf /*.
  • Массовое удаление по условию — через find с -delete, обязательно сначала посмотрев список без -delete.
  • Право на удаление даёт каталог, а не файл; если удаление не идёт при наличии прав — проверьте атрибут i через lsattr.

Похожие материалы

Shell и скрипты

Как распаковать tar.gz в Linux через терминал: tar, zip, xz и другие форматы

Короткий ответ — tar -xzf archive.tar.gz. Дальше разбираем, что означает каждая буква, как распаковать в нужный каталог, посмотреть содержимое до распаковки, вытащить один файл из большого архива и не поймать «tar-бомбу», которая раскидает сотни файлов по текущему каталогу.

Редакция
Shell и скрипты

Команда lsblk в Linux: как посмотреть диски, разделы и точки монтирования

lsblk показывает все блочные устройства сервера деревом: диски, разделы, LVM-тома, шифрованные контейнеры и куда они смонтированы. Разбираем колонки вывода, флаг -f для файловых систем и UUID, свои наборы колонок через -o и типовые задачи — найти новый диск, собрать строку для fstab, понять структуру LVM.

Редакция
Shell и скрипты

Команды vi в Linux: режимы, навигация, поиск и замена — шпаргалка

Начнём с главного: выйти из vi — это Esc, затем :q! без сохранения или :wq с сохранением. Дальше — рабочий минимум команд, которого хватает для правки конфигов на сервере: режимы, перемещение, удаление и вставка, поиск с заменой и трюк для сохранения файла, который открыли без sudo.

Редакция
Shell и скрипты

Как скопировать файл в Linux через терминал: cp, rsync и scp с примерами

Разбираем копирование в терминале: cp для файлов и каталогов, флаг -a для сохранения прав и симлинков, rsync для больших объёмов и докачки, scp для переноса на другой сервер. Плюс ловушки со слэшем в конце пути и скрытыми файлами, на которых теряют данные.

Редакция