find — это не только «найти файл»
В модуле 04-file-operations мы видели find как «инструмент поиска». Но у Junior DE 80% реальных задач с find — не найти, а почистить:
- удалить файлы старше N дней;
- сжать логи, к которым давно никто не обращался;
- найти и удалить пустые директории, оставшиеся после Spark _temporary;
- посчитать суммарный размер файлов по маске;
- найти большие файлы, не предусмотренные регламентом.
find подходит для этого идеально: он рекурсивен, поддерживает фильтры по любому атрибуту (имя, размер, время, владелец, тип), и умеет выполнять команды над найденным через -exec или -delete. Это makes it «швейцарский нож» disk-maintenance.
Базовый синтаксис: find PATH EXPRESSION
$ find PATH [FILTERS] [ACTIONS]
PATH — где искать (одна или несколько директорий). FILTERS — условия, какие файлы интересуют. ACTIONS — что делать (по умолчанию — -print, просто напечатать).
Простейший пример:
$ find /var/log -name '*.log'
Найдёт все файлы с расширением .log под /var/log. Без действий — просто список.
Фильтр -mtime: возраст файла
-mtime N — модификации N дней назад. Округление странное (по сути «полные сутки от текущего момента, не календарные»). Логика:
-mtime 0— модифицирован в последние 24 часа.-mtime 1— модифицирован 24-48 часов назад.-mtime +7— старше 7 дней (модифицирован больше 7*24=168 часов назад).-mtime -7— моложе 7 дней.
Аналогично:
-atime— access time (последнее чтение).-ctime— change time (метаданные: chown, chmod, rename).
Для секундной точности:
-mmin N— N минут назад.-mmin -60= модифицировано в последний час.-newer FILE— новее, чем указанный файл.-not -newer FILE— старше.
# Файлы /var/log/airflow, модифицированные больше 30 дней назад:
$ find /var/log/airflow -type f -mtime +30
# Файлы, изменённые в последний час:
$ find /tmp -type f -mmin -60
-atime обычно ненадёжен на современных Linux: ФС часто монтируются с relatime (atime обновляется только если предыдущий atime старше mtime/ctime). Это сделано ради производительности — не писать в inode на каждое чтение. Если нужен точный atime — нужна опция strictatime, но это редко используется.
Фильтр -size: размер файла
-size N[bckwMG]:
b(default) — 512-байтовые блоки.c— байты.k— KiB.M— MiB.G— GiB.
Знаки + и - работают как с mtime:
-size +100M— больше 100 МиБ.-size -1k— меньше 1 КиБ.-size 0— ровно 0 байт.
# Файлы больше 100 МБ под /var/log:
$ sudo find /var/log -type f -size +100M
# Пустые файлы (могли быть touch'нуты, но не дописаны):
$ find /data/staging -type f -size 0
# Файлы между 1 и 10 МБ:
$ find /data -type f -size +1M -size -10M
Action -delete: удалить найденное
# Удалить файлы старше 30 дней:
$ find /tmp -type f -mtime +30 -delete
# Удалить логи старше 14 дней:
$ sudo find /var/log/airflow -name '*.log' -mtime +14 -delete
-delete — необратимо. Всегда сначала запускай ту же команду без -delete и проверь, что найдено именно то, что надо. Опечатка в -mtime или -name может удалить production-данные.
# 1) Проверить, что найдём:
$ sudo find /var/log/airflow -name '*.log' -mtime +14
# 2) Если OK — добавить -delete:
$ sudo find /var/log/airflow -name '*.log' -mtime +14 -deleteAction -exec: выполнить произвольную команду
-exec CMD {} \; — для каждого найденного файла подставит его в {} и выполнит команду.
# Изменить владельца у всех файлов внутри:
$ sudo find /var/log/airflow -type f -exec chown airflow:airflow {} \;
# Установить права 0644:
$ sudo find /data/staging -type f -exec chmod 0644 {} \;
# Сжать каждый .log gzip-ом:
$ sudo find /var/log/airflow -name '*.log' -mtime +14 -exec gzip {} \;
\; — обязательный терминатор. Точка с запятой экранирована, чтобы shell её не интерпретировал. Можно вместо \; использовать + — тогда find соберёт группу файлов и подставит сразу пачкой:
# Медленнее: запускает rm для каждого файла отдельно (1000 запусков)
$ find /tmp -name 'cache_*' -exec rm {} \;
# Быстрее: rm с группой файлов (1 запуск с 1000 аргументов)
$ find /tmp -name 'cache_*' -exec rm {} +
На больших количествах файлов разница в десятки раз: запуск нового процесса (fork+exec) — дорогая операция.
-exec vs xargs vs -delete
Три способа делать что-то с найденным:
Все три работают, но имеют разные характеристики производительности и безопасности.
# Параллельная архивация — 8 процессов одновременно:
$ find /var/log/airflow -name '*.log' -mtime +14 -print0 \
| xargs -0 -n1 -P8 gzip
-P8 запускает до 8 параллельных процессов. Полезно для CPU-intensive операций (gzip, xz, image conversion).
DE-паттерны cleanup
1. Compress old logs (ротация)
Логи старше 14 дней сжать gzip-ом — экономия 5-20x места на текстовых логах:
$ sudo find /var/log/airflow -name '*.log' -mtime +14 -exec gzip {} +
После выполнения файлы станут .log.gz. Прозрачно читаются через zcat, zgrep.
Дальше старые .log.gz (старше 90 дней) можно удалить:
$ sudo find /var/log/airflow -name '*.log.gz' -mtime +90 -delete
Эти две команды вместе — основа большинства простых retention-политик. logrotate(8) делает то же самое в systemd, но из cron-скрипта оно проще и нагляднее.
2. Clean temp directories
Spark, Hive, Hadoop часто оставляют после себя _temporary директории, особенно если jobs прервался. Это типовой источник «диск кончился без видимой причины».
# Найти и удалить _temporary, не моложе 1 дня (на всякий случай не трогаем активные):
$ find /data/spark_temp -type d -name '_temporary' -mtime +1 -exec rm -rf {} +
# Пустые директории после Spark (обычно остаются после неудачных stages):
$ find /data/spark_temp -type d -empty -delete
-type d -empty -delete — удалить только пустые директории. find обходит дерево bottom-up при -delete (опция -depth неявно), поэтому если внутри директории были только пустые поддиректории — они тоже удалятся каскадно.
3. Найти большие файлы
Кто-то залил 50 ГБ дампа в /home/levo/Downloads, ты забыл и теперь диск 100%:
$ find ~ -type f -size +1G -exec du -h {} + | sort -hr | head
12G /home/levo/Downloads/db_dump_2024.sql
4.3G /home/levo/.cache/JetBrains/IDEAUltimate2024.1/index/
2.1G /home/levo/Videos/screencast.mkv
-exec du -h {} + — добавляет к найденному файлу его размер. sort -hr сортирует по убыванию. Топ-10 жирных файлов за 2 секунды.
4. Удалить пустые файлы
# Пустые .csv (часто результат неудачного ETL):
$ find /data/staging -type f -name '*.csv' -size 0 -delete
# Пустые директории:
$ find /data/staging -type d -empty -delete
5. Удалить файлы по владельцу
# Все файлы пользователя 'olduser', которого уже удалили:
$ sudo find /data -uid 1001 -delete
# Файлы без владельца (uid не существует — пользователь удалён):
$ sudo find /data -nouser
-uid 1001 — фильтр по числовому UID (выживает после удаления пользователя). -user olduser — по имени (не сработает, если пользователь уже удалён).
Полная DE-команда: rotate Airflow logs
Один cron-скрипт, который запускается каждую ночь:
#!/usr/bin/env bash
# /usr/local/bin/rotate-airflow-logs.sh
set -euo pipefail
LOGDIR=/var/log/airflow
# 1) Compress logs старше 14 дней
find "$LOGDIR" -type f -name '*.log' -mtime +14 -exec gzip {} + 2>/dev/null || true
# 2) Удалить gz старше 90 дней
find "$LOGDIR" -type f -name '*.log.gz' -mtime +90 -delete
# 3) Удалить пустые директории (после удаления старых файлов)
find "$LOGDIR" -mindepth 1 -type d -empty -delete
echo "[$(date -Iseconds)] rotate completed"
mindepth 1 нужен, чтобы случайно не удалить сам /var/log/airflow, если он окажется пустым (хотя обычно там подкаталоги).
Сохранение exit-code в || true после gzip нужно, чтобы скрипт не падал, если конкретный файл уже сжат или захвачен другим процессом — set -e иначе прервёт.
Про cron — модуль 15-cron-scheduling. Про set -euo pipefail — модуль 17-bash-scripting-advanced.
ncdu: интерактивный аудит диска
Для быстрого визуального аудита есть утилита ncdu (ncurses du):
$ sudo ncdu /var/log
Открывается полноэкранный интерфейс с деревом и размерами:
ncdu 1.20 ~ Use the arrow keys to navigate, press ? for help
--- /var/log ----------------------------------------
1.2 GiB [##########] /journal
892.3 MiB [####### ] /airflow
156.4 MiB [# ] /spark
24.1 MiB [ ] /postgres
12.0 MiB [ ] /nginx
8.4 MiB [ ] auth.log
240.0 KiB [ ] syslog
Управление:
- стрелки — навигация;
Enter— войти в директорию;d— удалить (с подтверждением);n— сортировка по имени,s— по размеру,c— по числу файлов;q— выйти.
Установка: apt install ncdu (Ubuntu/Debian), brew install ncdu (macOS).
ncdu — лучший инструмент для первого ответа на «диск кончился, что делать»: запустил, увидел жирных, удалил. Быстрее чем играть с du -sh /*/.
Альтернативы ncdu — современные TUI-инструменты: gdu (быстрее на больших ФС), dust (на Rust, цветные графики), duf (замена df -h с красивым UI). Любая из них — пять минут установить через apt/brew — экономит часы при debugging. Подробнее про модерные tools в модуле 18-productivity-modern-tools.
Анти-паттерны при cleanup
НИКОГДА не делай так
# 1) rm -rf без проверки пути:
$ cd /var/log/airflow; rm -rf *
# Если cd упал (нет директории), окажешься в $HOME — снесёшь свой home.
# Всегда: ls сначала, потом rm. Или абсолютные пути.
# 2) find / без фильтров с -delete:
$ sudo find / -size +100M -delete
# Уничтожит критичные большие файлы: kernel image, vmlinuz, sqlite базы.
# 3) -delete до проверки:
$ find /data -mtime +1 -delete # опечатка в пути? потерял свежие данные.
Безопасный workflow
- Сначала запусти find без
-delete/-exec— посмотри список. - Запусти с
-exec ls -la {} \;или... | head— проверь. - Только потом добавляй
-delete.
# Step 1: что вообще найдётся?
$ find /var/log/airflow -name '*.log' -mtime +14 | head -20
# Step 2: сколько весит?
$ find /var/log/airflow -name '*.log' -mtime +14 -exec du -h {} + | sort -hr | head
# Step 3: всё сошлось — удаляем
$ find /var/log/airflow -name '*.log' -mtime +14 -delete
Попробуй сам
- Найди файлы старше 7 дней в
/tmp:find /tmp -type f -mtime +7 - Топ-10 самых больших файлов в твоей home:
find ~ -type f -size +10M -exec du -h {} + 2>/dev/null | sort -hr | head -10 - Удалить пустые директории в
~/projects:find ~/projects -type d -empty -delete - Сжать все
.txtстарше 30 дней (если у тебя такие есть):find ~/notes -name '*.txt' -mtime +30 -exec gzip {} + - Запусти
ncduна одной из своих папок:ncdu ~/Downloads
macOS-различия
- macOS использует BSD-find, у которого синтаксис
-mtime/-sizeтот же, но некоторые опции отличаются (-printfотсутствует, нужен-print+awk). -deleteработает.-exec ... +поддерживается.- Для GNU-find на macOS:
brew install findutils, потомgfind(или alias-нутьfind=gfindв shell config). ncdu—brew install ncdu.
Главное
find— главный инструмент cleanup. Фильтры (-mtime,-size,-name) + действия (-delete,-exec).-mtime +N— старше N дней.-mtime -N— моложе.-mminдля минут.-size +100M— больше 100 МиБ.0— пустой. Знаки+/-работают везде.-delete— быстро, безопасно (не делает fork). Необратимо — всегда сначала проверь без-delete.-exec CMD {} +— батчем, быстро.-exec CMD {} \;— по одному, медленно.- Параллельные действия:
find ... -print0 | xargs -0 -P8 CMD. - DE-паттерны: ротация
find ... -mtime +N -exec gzip {} +, удаление старых архивов, очистка_temporary, поиск больших файлов. ncdu(илиgdu,dust) — интерактивный TUI для аудита. Лучший first response на «диск 100%».- Безопасный workflow: запусти find без
-delete, проверь, потом удаляй.