Linux удаление больших файлов

Как удалить большое количество файлов в Linux

Удалять файлы можно используя утилиту find, в отличие от ls или rm с указанием маски она не формирует изначально список содержимого каталога, а перебирает файлы по одному.

Посчитать количество файлов можно так

find /home/web/example.com/www/opt/cache/ -type f ¦ wc -l

С -exec rm -f можно запустить процесс удаления файлов (он может занять длительное время)

find /home/web/example.com/www/opt/cache/ -type f -exec rm -f <> \;

Можно попробовать find с опцией delete

find /home/web/example.com/www/opt/cache/ -type f -delete

Скорее всего не даст никакого результата rm с указанием файлов по маске — система при этом до того как начать удаление попытается сформировать полный список файлов, что сделать не получится

Также существует вариант с ls -f, вывод которого перенаправляется в xargs по 100 файлов, затем удаляемых при помощи rm. Может успешно отрабатывать, однако если файлов слишком много вывести список не получится и с ls -f

cd /home/web/example.com/www/opt/cache/ ; ls -f . | xargs -n 100 rm

Самой эффективной командой обычно оказывается find с -exec rm -f, однако все зависит от количества файлов и использовать стоит все представленные варианты (приоритет процессов при удалении имеет смысл максимально понижать используя nice и ionice — алиасы для find или других команд можно добавить в .bashrc пользователя, от имени которого производится удаление).

Источник

Команды для удаления большого количества файлов в Linux

Удаление старых файлов linux по маске чаще всего осуществляется следующим образом:

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

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

Если rm -rf не помогает — удалять файлы следует в цикле for. Для каждого файла будет отдельная операция удаления и никаких ограничений системы здесь ожидать не приходится.

Синтаксис в простейшем случае может выглядеть так:

for f in /var/log/apache2/*.log; do rm «$f»; done

В цикл for можно добавить любую дополнительную логику.

Удаление старых файлов в Linux по Cron

Логи или другие файлы (сессии РНР) можно удалять как используя циклы (так приходится делать обычно если логов или других файлов накопилось действительно очень много), но если система не запущена или только создается лучше использовать регулярно выполняемое задание Cron, согласно которому с заданной периодичностью будут удаляться файлы определенных типов

# m h dom mon dow command

23 3 * * * find /var/www/web/sites/server-gu.ru/www/var/session/ -type f -mtime 7 -exec rm -f <> \;

В примере удаляются сессии РНР для сайта старше 7 дней.

В цикле то же самое можно сделать так:

for f in /tmp/logs/*.log

find $f -mtime +7 -exec rm <> \;

Приведенное выражение, как и любой другой цикл можно поместить в файл, сделать его исполняемым и с тем же успехом выполнять по Cron

Читайте также:  Windows 10 мышь не открывает папки

Источник

Необычное переполнение жесткого диска или как удалить миллионы файлов из одной папки

Предисловие

Начало

Ничто не предвещало беды.
Сервер с сайтом работал без никаких проблем уже больше года (uptime почти 500 дней), не было никаких проблем, и я с чистой душой спокойно ушел в отпуск.

В первый же день отпуска мне звонят с жалобой — сайт недоступен. MySQL падает с ошибкой Error 28 «No space left on device».

Казалось бы, проблема банальна — кончилось место на диске. Правда, df -h показывает, что на диске имеется вполне достаточное количество свободного места, ну да я же в отпуске, разбираться лень — посоветовал им поискать на диске ненужные файлы (старые бекапы и т.д.) и их удалить. Удалили, вроде все заработало.

Прошла пара часов и проблема вернулась. Странно — свободное место на жестком диске за это время практически не уменьшилось. После беглого гугления обнаружился топик на serverfault, в котором говорится, что проблема может возникнуть также из-за того, что кончилось не место на диске, а айноды!

Ввожу в консоль df -i — и оказывается действительно, айноды у меня закончились.

Проблема

Начал искать, где же у меня находится столько файлов на жестком диске, что они сожрали все айноды (а айнодов у меня на 500-гигабайтном жестком диске больше 30 миллионов).

И нашел — оказалось, проблема была в папке с сессиями php.

Видимо, по какой-то причине сломался механизм автоочистки этой папки, что привело к тому, что в ней скопилось огромное количество файлов. Насколько огромное — сказать сложно, потому что никакие стандартные команды линукс, такие, как ls, find, rm и т.д. — с этой папкой не работают. Просто виснут, заодно подвешивая весь сервер. Могу только сказать, что сам файл директории стал весит около гигабайта, а также что файлов там точно более полумиллиона, потому что столько я оттуда уже удалил.

Решение

Решение очевидное — надо удалить все эти файлы сессий. При этом желательно, чтобы сервер продолжал работать в штатном режиме. Для начала я переименовал папку сессий, в которой лежит куча файлов, а вместо нее создал пустую — чтобы спокойно из старой (переименованной) удалять все файлы, и чтобы это не мешало созданию новых файлов сессий.

Также в крон добавил автоматическое удаление файлов сессий старше одного часа, чтобы проблема больше не повторилась.

И перешел к основной проблеме — очистке жесткого диска.

Попробовал решение «в лоб»:

Сервер повис, ничего не удалилось

Попробовал известный способ для удаления большого числа файлов

Ничего, сервер виснет, файлы не удаляются.

А теперь что самое интересное — файловый менеджер mc достаточно успешно справлялся с задачей удаления этих файлов! То есть, когда запускаешь удаление папки — файлы удаляются, mc не виснет. Удаление идет со скоростью примерно 5 000 файлов в минуту, правда при этом создается огромная нагрузка на жесткий диск, что приводит к неработоспособности сервера.

А хотелось бы, чтобы эти файлы постепенно удалялись в фоновом режиме, и не мешали нормальной работе сайта.

Собственно, решение опять нашлось в гугле — Olark делится способом, как он отобразил список из 8 миллионов файлов в 1 папке, используя системный вызов getdents

Здесь находится документация по функции getdents, а также пример кода, который ее использует.

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

Читайте также:  Как полностью выключить брандмауэр windows

Опытным путем подобрал размер буфера в 30 килобайт, который позволяет считать около 550 названий файлов из директории, при этом не подвешивая сервер и не создавая излишней нагрузки на диск. А также немного переписал код примера, чтобы вместо отображения имени файла он его удалял.

В итоге у меня получился такой код:

Код компиллируется обычным gcc

И просто запускается из командной строки:

Получившийся файл я поставил в крон и теперь у меня удаляется по 547 файлов в минуту, при этом нагрузка на сервер в пределах нормы — и я надеюсь, в течение недели-другой все файлы все-таки удалятся.

Источник

Так как же удалить миллионы файлов из одной папки?


Феерическая расстановка точек над i в вопросе удаления файлов из переполненной директории.

Прочитал статью Необычное переполнение жесткого диска или как удалить миллионы файлов из одной папки и очень удивился. Неужели в стандартном инструментарии Linux нет простых средств для работы с переполненными директориями и необходимо прибегать к столь низкоуровневым способам, как вызов getdents() напрямую.

Для тех, кто не в курсе проблемы, краткое описание: если вы случайно создали в одной директории огромное количество файлов без иерархии — т.е. от 5 млн файлов, лежащих в одной единственной плоской директории, то быстро удалить их не получится. Кроме того, не все утилиты в linux могут это сделать в принципе — либо будут сильно нагружать процессор/HDD, либо займут очень много памяти.

Так что я выделил время, организовал тестовый полигон и попробовал различные средства, как предложенные в комментариях, так и найденные в различных статьях и свои собственные.

Подготовка

Так как создавать переполненную директорию на своём HDD рабочего компьютера, потом мучиться с её удалением ну никак не хочется, создадим виртуальную ФС в отдельном файле и примонтируем её через loop-устройство. К счастью, в Linux с этим всё просто.

Создаём пустой файл размером 200Гб

Многие советуют использовать для этого утилиту dd, например dd if=/dev/zero of=disk-image bs=1M count=1M , но это работает несравнимо медленнее, а результат, как я понимаю, одинаковый.

Форматируем файл в ext4 и монтируем его как файловую систему

К сожалению, я узнал об опции -N команды mkfs.ext4 уже после экспериментов. Она позволяет увеличить лимит на количество inode на FS, не увеличивая размер файла образа. Но, с другой стороны, стандартные настройки — ближе к реальным условиям.

Создаем множество пустых файлов (будет работать несколько часов)

Кстати, если в начале файлы создавались достаточно быстро, то последующие добавлялись всё медленнее и медленнее, появлялись рандомные паузы, росло использование памяти ядром. Так что хранение большого числа файлов в плоской директории само по себе плохая идея.

Проверяем, что все айноды на ФС исчерпаны.

Размер файла директории

Теперь попробуем удалить эту директорию со всем её содержимым различными способами.

Тесты

После каждого теста сбрасываем кеш файловой системы
sudo sh -c ‘sync && echo 1 > /proc/sys/vm/drop_caches’
для того чтобы не занять быстро всю память и сравнивать скорость удаления в одинаковых условиях.

Удаление через rm -r

$ rm -r /mnt/test_dir/
Под strace несколько раз подряд (. ) вызывает getdents() , затем очень много вызывает unlinkat() и так в цикле. Занял 30Мб RAM, не растет.
Удаляет содержимое успешно.

Т.е. удалять переполненные директории с помощью rm -r /путь/до/директории вполне нормально.

Удаление через rm ./*

$ rm /mnt/test_dir/*
Запускает дочерний процесс шелла, который дорос до 600Мб, прибил по ^C . Ничего не удалил.
Очевидно, что glob по звёздочке обрабатывается самим шеллом, накапливается в памяти и передается команде rm после того как считается директория целиком.

Удаление через find -exec

$ find /mnt/test_dir/ -type f -exec rm -v <> \;
Под strace вызывает только getdents() . процесс find вырос до 600Мб, прибил по ^C . Ничего не удалил.
find действует так же, как и * в шелле — сперва строит полный список в памяти.

Читайте также:  Remove all users from group linux

Удаление через find -delete

$ find /mnt/test_dir/ -type f -delete
Вырос до 600Мб, прибил по ^C . Ничего не удалил.
Аналогично предыдущей команде. И это крайне удивительно! На эту команду я возлагал надежду изначально.

Удаление через ls -f и xargs

$ cd /mnt/test_dir/ ; ls -f . | xargs -n 100 rm
параметр -f говорит, что не нужно сортировать список файлов.
Создает такую иерархию процессов:

ls -f в данной ситуации ведет себя адекватнее, чем find и не накапливает список файлов в памяти без необходимости. ls без параметров (как и find ) — считывает список файлов в память целиком. Очевидно, для сортировки. Но этот способ плох тем, что постоянно вызывает rm , чем создается дополнительный оверхед.
Из этого вытекает ещё один способ — можно вывод ls -f перенаправить в файл и затем удалить содержимое директории по этому списку.

Удаление через perl readdir

$ perl -e ‘chdir «/mnt/test_dir/» or die; opendir D, «.»; while ($n = readdir D) < unlink $n >‘ (взял здесь)
Под strace один раз вызывает getdents() , потом много раз unlink() и так в цикле. Занял 380Кб памяти, не растет.
Удаляет успешно.

Получается, что использование readdir вполне возможно?

$ gcc -o cleandir cleandir.c
$ ./cleandir
Под strace один раз вызывает getdents() , потом много раз unlink() и так в цикле. Занял 128Кб памяти, не растет.
Удаляет успешно.

Опять — же, убеждаемся, что использовать readdir — вполне нормально, если не накапливать результаты в памяти, а удалять файлы сразу.

Источник

Как быстро удалить Очень Много файлов?

Есть раздел под XFS. В нём директория. Выглядит так:

# ls -ldh .
drwxrwxrwx 2 user user 330M Aug 4 01:04

Т.е. только мета-инфа весит 330 Мб (верхняя планка, значит, 1,3-1,4 млн. файлов). Списка имён файлов нет.

Вопрос: как их быстро удалить, с минимальной утилизацией винтов (продакшн-сервер) и без потери остальных данных на этом разделе?

Re: Как быстро удалить Очень Много файлов?

rm -dfr /var/www или че там у тебя

Каждую неделю вопрос на ЛОРе.

Этого вопроса ещё нет в FAQ? (Мне лень смотреть)

find . -maxdepth 1 -type f | xargs -0 ls

Use ionice, Luke!

> Т.е. только мета-инфа весит 330 Мб

Неверно, но к делу отношения не имеет.

> Вопрос: как их быстро удалить,

rm -rf /path/to/dir

> с минимальной утилизацией винтов (продакшн-сервер)

echo cfq > /sys/block/[диск, где находится ФС]/queue/scheduler

ionice -c3 rm -rf /path/to/dir

P.S. Непонятно, чем они так помешали, что понадобилось их так срочно удалять.

Re: Как быстро удалить Очень Много файлов?

Спасибо. С -d всё хорошо.

До этого пробовал:
#find ./ -maxdepth 1 -type f -mtime +7 -exec rm -f <> \;
(не хотелось удалять всё), выглядело так:
——————
#strace -s 360 -p 25670
Process 25670 attached — interrupt to quit
getdents64(4, /* 73 entries */, 4096) = 4088
getdents64(4, /* 73 entries */, 4096) = 4088
getdents64(4, /* 73 entries */, 4096) = 4088
getdents64(4, /* 73 entries */, 4096) = 4088
getdents64(4, /* 73 entries */, 4096) = 4088
etdents64(4,
Process 25670 detached
——————
, т.е. видимо строило файл-лист и делало это больше недели, с обычным rm было так же (надо было кстати использование памяти замерить).
А с ionice -c3 rm -dfr dir так:
# strace -s 360 -p 933
——————
Process 933 attached — interrupt to quit
unlink(«4e2a0e62921574187660e5ea2155af7e») = 0
unlink(«6094ad144713c973537c162b9e52b5d5») = 0
unlink(«86287687383af5b9c880cd6d4dbaca1c») = 0
unlink(«a8c6a06559e542e396c01a28d6110bbc») = 0
unlink(«ce40f028183e656e1fb5039b8a06dc92») = 0
unlink(«6c66c8ac651afbcd9c3b6dd45a79d506») = 0
unlink(«0753b1f1fcadc9262f0705c897350846») = 0
unlink(«a76ec71296a85087c5e76c413c92e23b») = 0
unlink(«66d65eba60a15d3e44b4058c763dbe74») = 0
— SIGINT (Interrupt) @ 0 (0) —
Process 933 detached
——————

Источник

Оцените статью