Learning Platform
Глоссарий Troubleshooting
Урок 15.03 · 22 мин
Начальный
findcleanupmtimesizencdulog rotationdata engineering

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
NOTE

-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
WARNING

-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 -delete

Action -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

Три способа делать что-то с найденным:

Способы action в find

Все три работают, но имеют разные характеристики производительности и безопасности.

-deleteсамый быстрый, безопасный
-exec CMD {} ;по одному файлу — медленно
-exec CMD {} +батчем — быстро
| xargs -0для xargs-фич: -P parallel
# Параллельная архивация — 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-скрипта оно проще и нагляднее.

Docker volumes cleanup — аналогичная задача управления lifecycle данных

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 /*/.

TIP

Альтернативы 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

  1. Сначала запусти find без -delete/-exec — посмотри список.
  2. Запусти с -exec ls -la {} \; или ... | head — проверь.
  3. Только потом добавляй -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

Попробуй сам

  1. Найди файлы старше 7 дней в /tmp:
    find /tmp -type f -mtime +7
  2. Топ-10 самых больших файлов в твоей home:
    find ~ -type f -size +10M -exec du -h {} + 2>/dev/null | sort -hr | head -10
  3. Удалить пустые директории в ~/projects:
    find ~/projects -type d -empty -delete
  4. Сжать все .txt старше 30 дней (если у тебя такие есть):
    find ~/notes -name '*.txt' -mtime +30 -exec gzip {} +
  5. Запусти 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).
  • ncdubrew 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, проверь, потом удаляй.

Проверьте понимание

Результат: 0 из 0
Прикладной
Вопрос 1 из 5. Нужно сжать gzip-ом все .log файлы старше 14 дней в /var/log/airflow. Какая команда наиболее эффективна?

Закончили урок?

Отметьте его как пройденный, чтобы отслеживать свой прогресс

Войдите чтобы оценить урок

Прогресс модуля
0 из 4