Learning Platform
Глоссарий Troubleshooting
Урок 05.04 · 22 мин
Начальный
findlocatewhichfdSearch

find, locate, which: поиск файлов

«Где лежит этот файл?» — типичный вопрос Junior DE. Большой data lake, тысячи папок, файлы создаются автоматически — без инструментов поиска работать невозможно. В этом уроке: find (мощный, но капризный), locate (быстрый, но требует индекса), which/whereis/type (для команд), и fd (modern замена find).


find: швейцарский нож поиска

find DIR [tests] [actions] — это шаблон. Команда обходит дерево директорий и применяет тесты к каждому файлу. Для тех, кто проходит тесты — выполняет actions.

Базовый вызов:

$ find . -name "*.csv"
./data/raw.csv
./data/processed/2026-05-13.csv
./backup/old.csv

. — где искать (текущая директория и рекурсивно вниз). -name "*.csv" — тест по имени. Action по умолчанию — -print (вывести путь).


Тесты find: что искать

Главные тесты find
-name 'pattern'Имя файла по shell-glob паттерну. `-name '*.log'`, `-name 'data*.csv'`. Чувствителен к регистру
-iname 'pattern'То же, но регистр игнорируется. `-iname '*.JPG'` найдёт .jpg, .Jpg, .JPG
-type f / d / lf — обычный файл, d — directory, l — symlink. Без -type найдёт всё подряд
-size +100MБольше 100MB. `-size -1k` (меньше 1KB), `+1G` (больше гигабайта). Без знака — точное
-mtime -7Изменены за последние 7 дней. `+30` — старше 30 дней, `-1` — за последние сутки. Также -atime, -ctime
-perm 0644С точными правами. -perm /u+w — есть write для владельца. -perm -0444 — есть read для всех
-user aliceВладелец. `-group dev` — группа. `-nogroup`/`-nouser` — orphan files после удаления пользователя
-emptyПустые файлы/папки. Полезно для очистки
-path 'pattern'Полный путь матчится паттерном. `-path '*/node_modules/*' -prune -o ...` — exclude
-not / !Отрицание. `-not -name '*.log'` — всё, кроме .log
-and / -aИ (по умолчанию). `-name '*.csv' -size +1M`
-or / -oИЛИ. `\\( -name '*.log' -o -name '*.tmp' \\)`. Группировка через \\(...\\)

Комбинируются:

# Большие CSV изменённые за неделю
$ find /var/data -name "*.csv" -size +100M -mtime -7 -type f
/var/data/2026-05-12/sales.csv
/var/data/2026-05-13/users.csv

# Все .log или .tmp старше 30 дней
$ find /var/log \( -name "*.log" -o -name "*.tmp" \) -mtime +30

# Пустые папки
$ find /tmp -type d -empty

# Не в node_modules
$ find . -name "*.py" -not -path "*/node_modules/*"

# С определёнными правами
$ find /etc -perm 0644 -type f

Actions find: что делать

-print — по умолчанию. Можно явно. Другие actions:

# Удалить найденные
$ find /tmp -name "*.tmp" -mtime +7 -delete
# или с execute:
$ find /tmp -name "*.tmp" -mtime +7 -exec rm {} \;

# Запустить команду на каждом найденном
$ find . -name "*.py" -exec wc -l {} \;
247 ./main.py
89 ./utils.py
...

# Скопировать
$ find /var/data -name "*.csv" -exec cp {} /backup/ \;

В -exec {} — это placeholder для найденного файла. \; (или ;) — конец команды.

Есть две формы -exec:

# Одна команда на файл (медленно при тысячах файлов)
$ find . -name "*.csv" -exec gzip {} \;

# Все файлы за раз (как xargs)
$ find . -name "*.csv" -exec gzip {} +

Знак + в конце вместо \; — гораздо быстрее (одна команда вместо тысячи).


-exec vs xargs

Альтернатива — xargs:

# Через xargs
$ find . -name "*.csv" | xargs gzip

# Безопасный вариант с пробелами в именах
$ find . -name "*.csv" -print0 | xargs -0 gzip

-print0 выводит имена, разделённые null-байтами (\0), а не переводами строк. xargs -0 это парсит. Это решает проблему пробелов и спецсимволов в именах.

WARNING

ВСЕГДА используйте -print0 | xargs -0 если есть шанс, что в именах файлов будут пробелы или специальные символы. Без этого find . | xargs сломается на файле “report with spaces.csv” — он разобьётся на три аргумента: ‘report’, ‘with’, ‘spaces.csv’.


Реальный DE-сценарий

Допустим, у вас data lake, и нужно: удалить все CSV-файлы старше 30 дней в /var/data/raw/, но только если они меньше 10MB (большие должны архивироваться отдельно).

$ find /var/data/raw \
    -name "*.csv" \
    -type f \
    -size -10M \
    -mtime +30 \
    -delete

Это одна команда, которая:

  1. Идёт по /var/data/raw/ и подпапкам.
  2. Берёт только .csv файлы (-name, -type f).
  3. Только меньше 10MB (-size -10M).
  4. Только старше 30 дней (-mtime +30).
  5. Удаляет (-delete).

В cron это уйдёт раз в неделю и будет чистить старые данные.

CronJob в Kubernetes — планирование задач очистки

find: ловушки

  1. Порядок аргументов важен. -name должен быть перед -type, -delete — после. Если -delete поставить в начало — удалит ВСЁ, что нашёл, до фильтров.
# ОПАСНО! Удаляет ВСЁ в /tmp!
$ find /tmp -delete -name "*.tmp"

# Правильно:
$ find /tmp -name "*.tmp" -delete
  1. -name чувствителен к регистру. -name "*.csv" не найдёт data.CSV. Используйте -iname.

  2. -name работает только с базовым именем. -name "/path/to/file" НЕ работает. Используйте -path или -wholename.

  3. Symlinks. По умолчанию find НЕ переходит по symlinks. Чтобы переходить — -L (перед путём): find -L /etc -name "*.conf".

  4. На macOS find — BSD-вариант. -mtime, -name, -type работают. Но -delete есть. Нет -print0 — нужно через -exec echo {} \;.


Производительность find

Для маленьких деревьев find мгновенный. Для больших (миллионы файлов) — может занять минуты. Что замедляет:

  • Глубокое дерево.
  • -exec cmd {} \; (одна команда на файл).
  • Медленный диск.

Что ускоряет:

  • Указать -maxdepth N (ограничить глубину).
  • Использовать -exec cmd {} + или xargs (batch).
  • Использовать locate или fd вместо find для интерактивного поиска (об этом ниже).
# Только текущая папка и одна вложенная
$ find /var/log -maxdepth 2 -name "*.log"

# Только директории на верхнем уровне
$ find /home -maxdepth 1 -type d

locate: быстрый поиск через индекс

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

$ locate passwd
/etc/passwd
/etc/passwd-
/etc/cron.daily/passwd
/usr/share/man/man1/passwd.1.gz
/usr/share/man/man5/passwd.5.gz
...

Это нашло мгновенно — потому что прочитало из индексной БД, не обходя FS.

Минусы:

  1. Индекс может устареть. Если только что создали файл — locate не найдёт, пока не обновится индекс.
  2. Найдёт всё, что было. Если файл удалён, но индекс не пересчитан — locate его покажет.
  3. Требует установки и индекса.

Обновление индекса:

$ sudo updatedb
# 30 секунд - 2 минуты, в зависимости от системы

# Cron обычно обновляет ежедневно (/etc/cron.daily/mlocate)

Когда использовать:

  • Для быстрого поиска «где приблизительно лежит файл с именем X».
  • Не для свежесозданных файлов.
  • Не для скриптов (ненадёжно).
# Установить если нет
$ sudo apt install -y mlocate
$ sudo updatedb
$ locate sshd_config
/etc/ssh/sshd_config

which / whereis / type: где команда

Поиск исполняемого файла команды:

$ which python3
/usr/bin/python3

$ which ls
/usr/bin/ls

$ type python3
python3 is /usr/bin/python3

$ type ls
ls is aliased to `ls --color=auto'

Разница:

which vs type vs whereis
whichВнешняя программа. Только ищет в PATH. Не знает про aliases, builtins, functions
typeBuiltin bash. Показывает ВСЁ: alias, function, builtin, file. Лучшая для отладки 'почему команда странно работает'
whereisИщет binary, man-page и source code. Например `whereis ls` найдёт /usr/bin/ls + /usr/share/man/man1/ls.1.gz
$ alias ll='ls -la'

$ which ll
# (ничего, потому что which не знает про aliases)

$ type ll
ll is aliased to `ls -la'

$ type cd
cd is a shell builtin

$ type python3
python3 is /usr/bin/python3

Используйте type, а не which. type показывает реальную картину.


fd: modern замена find

fd — это переписанный на Rust find, с упрощённым синтаксисом и лучшими defaults:

$ sudo apt install -y fd-find    # на Debian/Ubuntu (команда называется fdfind)
$ alias fd=fdfind
# или
$ brew install fd                # на macOS

# Простой поиск:
$ fd 'main\.py'
./src/main.py
./tests/main.py

# По расширению:
$ fd -e csv
./data/raw.csv
./data/processed.csv

# С regex:
$ fd '^[0-9]{4}\.log$' /var/log
/var/log/2024.log
/var/log/2025.log

# С action:
$ fd -e csv -x gzip
# для каждого .csv запускает gzip

Чем fd лучше find:

  • Простой синтаксис: fd 'pattern' вместо find . -name 'pattern'.
  • По умолчанию игнорирует: .git, node_modules, .gitignore-файлы (как ripgrep).
  • Цветной вывод.
  • В 5-10 раз быстрее на больших деревьях (multithreaded).
  • Лучшая обработка пробелов в именах.

Для интерактивного поиска fd — однозначный winner. Для production-скриптов всё ещё лучше find (есть везде, не требует установки).


Попробуй сам

Создайте песочницу:

$ mkdir -p ~/linux-sandbox/lesson-find/{data,logs,backups}
$ cd ~/linux-sandbox/lesson-find

# Создадим разные файлы
$ touch data/{a,b,c}.csv
$ touch data/big.csv && dd if=/dev/zero of=data/big.csv bs=1M count=10 2>/dev/null
$ touch logs/{error,access}.log
$ touch backups/old.tar.gz
$ touch "file with spaces.txt"

# Базовый поиск
$ find . -name "*.csv"

# По размеру (большие)
$ find . -size +1M

# По времени (созданные за последний час)
$ find . -mmin -60

# Type filter
$ find . -type d         # только папки
$ find . -type f         # только файлы

# С execute (count lines в каждом)
$ find . -name "*.csv" -exec wc -l {} +

# С null-separated (правильно для пробелов)
$ find . -name "*.txt" -print0 | xargs -0 -I {} echo "FILE: {}"

Сравните производительность locate и find:

$ sudo updatedb
$ time locate passwd
real    0m0.012s

$ time find / -name "passwd" 2>/dev/null
real    0m3.421s   # в 300 раз медленнее

Поставьте и попробуйте fd:

$ sudo apt install -y fd-find
$ fdfind 'csv$'
$ fdfind -e log

Проверка знанийKnowledge check
DE-команда жалуется: 'cron-задача `find /var/data -name *.csv -mtime +30 -delete` ничего не удаляет, хотя файлы старые есть'. В чём может быть проблема?
ОтветAnswer
Несколько возможных причин. (1) Глобальный glob: `*.csv` в команде разворачивается shell-ом ДО запуска find, если в текущем каталоге есть файлы .csv — то они подставятся, а если нет — то `-name *.csv` остаётся как литералы (find получит несколько аргументов из глоба). Правильно: `-name '*.csv'` в кавычках, чтобы find сам разворачивал паттерн. (2) Path issue: `/var/data` может не существовать или быть пустым (актуально, если каталог монтируется по сети и не примонтирован). (3) Права: cron запускает от root, но если cron работает от другого user без прав на /var/data, ничего не найдёт. (4) Время изменения: `-mtime +30` означает 'старше 30 дней по mtime' — если файлы регулярно обновляются (touch при записи), mtime свежий и они не подпадают. Правильнее `-mmin +43200` или с -atime. (5) Логирование: добавить `-print` ПЕРЕД `-delete` чтобы видеть в логе, что удаляется. Полная исправленная команда: `find /var/data -name '*.csv' -type f -mtime +30 -print -delete 2>&1 | tee -a /var/log/cleanup.log`. Это даст полный аудит того, что произошло.

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

Результат: 0 из 0
Прикладной
Вопрос 1 из 5. Какая команда найдёт все .csv файлы больше 100MB, изменённые за последнюю неделю?

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

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

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

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