Базовый синтаксис
find [PATH...] [EXPRESSION]
Если PATH опущен - берётся текущий каталог. EXPRESSION - цепочка предикатов
и действий, склеиваемых неявным -and.
find . # все файлы и каталоги от .
find /var/log -type f # только файлы (не каталоги)
find ~ -name '*.log' # по имени, glob-паттерн
find / -maxdepth 2 -type d # каталоги, не глубже 2-го уровня
Предикаты по типу
| предикат | значение |
|---|---|
-type f | обычный файл |
-type d | каталог |
-type l | symlink (см. symbolic-link) |
-type s | socket |
-type p | named pipe (FIFO) |
-type b / -type c | block / character device |
Имя и путь
find . -name '*.py' # имя по glob
find . -iname '*.PY' # как -name, но без учёта регистра
find . -path '*/tests/*.py' # полный путь по glob
find . -regex '.*/test_[0-9]+\.py' # POSIX-regex по полному пути
Кавычки обязательны - иначе шелл сам раскроет * до того как find их
увидит.
По времени
Время в find - в сутках для базовых флагов и в минутах для
-mmin/-amin/-cmin. Знаки: -N (меньше N), +N (больше N), N (ровно N).
| флаг | что |
|---|---|
-mtime N | modified N дней назад |
-atime N | last access N дней назад |
-ctime N | metadata changed N дней назад (см. inode) |
-mmin N | modified N минут назад |
-newer FILE | новее чем FILE |
find /var/log -type f -mtime -1 # изменены за последние 24 часа
find /tmp -type f -mtime +7 # старше недели - кандидаты на чистку
find . -mmin -10 # тронуты за последние 10 минут
find . -newer Makefile # всё что новее Makefile
По размеру
Суффиксы: c (байты), k (КиБ), M (МиБ), G (ГиБ).
find . -type f -size +100M # файлы крупнее 100 МиБ
find /var/log -type f -size +10M -size -100M # 10..100 МиБ
find . -type f -empty # пустые файлы
find . -type d -empty # и пустые каталоги
По правам и владельцу
find . -type f -perm -u+x # с битом execute у владельца
find . -perm -4000 # SUID-файлы (см. [[file-permissions]])
find /etc -user root -group root
find /home -nouser -o -nogroup # «осиротевшие» (orphan UID/GID)
Действия
По умолчанию find печатает пути (-print). Альтернативы:
find . -name '*.tmp' -delete # удалить (встроенное действие)
find . -name '*.log' -exec gzip {} \; # exec на КАЖДЫЙ файл по отдельностиfind . -name '*.log' -exec gzip {} + # пакетно (быстрее, как xargs)find . -type f -print0 | xargs -0 wc -l # классический pattern с -print0
Разница \; vs +:
\;- запускает команду один раз на файл (медленно если файлов тысячи)+- собирает аргументы пачкой и запускает реже (правильный выбор по умолчанию)
-print0 + xargs -0
Если в именах могут быть пробелы или переводы строк - обычный xargs
сломается. Решение - нулевой разделитель:
find . -type f -name '*.log' -print0 | xargs -0 grep -l 'ERROR'
Это найдёт во всех .log файлах те, где встречается ERROR - частая
связка с cmd-grep.
Логика
find . \( -name '*.tmp' -o -name '*.bak' \) -delete # OR через -o, скобки экранировать
find . -name '*.py' -not -path '*/venv/*' # NOT через -not (или !)
find . -type f -name '*.log' -size +1M # неявный AND
fd как современная альтернатива
fd (fd-find пакет) - простая обёртка с лучшими defaults: умеет .gitignore,
цвет, parallel, -x для exec. Если есть в системе - fd '\.py$' src короче
и быстрее. Но find есть везде из коробки, поэтому учить базу всё равно надо.