# find - поиск файлов по предикатам _Команды · LinuxLab Knowledge Base_ **TL;DR:** `find` обходит дерево каталогов и применяет предикаты (имя, тип, время, размер, права). Действия: `-print` (по умолчанию), `-delete`, `-exec`, `| xargs`. ## Базовый синтаксис ``` find [PATH...] [EXPRESSION] ``` Если PATH опущен - берётся текущий каталог. EXPRESSION - цепочка предикатов и действий, склеиваемых неявным `-and`. ```bash 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](/kb/symbolic-link.md)) | | `-type s` | socket | | `-type p` | named pipe (FIFO) | | `-type b` / `-type c` | block / character device | ## Имя и путь ```bash 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](/kb/inode.md)) | | `-mmin N` | modified N минут назад | | `-newer FILE` | новее чем FILE | ```bash 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` (ГиБ). ```bash 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 # и пустые каталоги ``` ## По правам и владельцу ```bash find . -type f -perm -u+x # с битом execute у владельца find . -perm -4000 # SUID-файлы (см. [file-permissions](/kb/file-permissions.md)) find /etc -user root -group root find /home -nouser -o -nogroup # «осиротевшие» (orphan UID/GID) ``` ## Действия По умолчанию `find` печатает пути (`-print`). Альтернативы: ```bash 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` сломается. Решение - нулевой разделитель: ```bash find . -type f -name '*.log' -print0 | xargs -0 grep -l 'ERROR' ``` Это найдёт во всех `.log` файлах те, где встречается `ERROR` - частая связка с [cmd-grep](/kb/cmd-grep.md). ## Логика ```bash 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` есть везде из коробки, поэтому учить базу всё равно надо. ## Команды ```bash find . -type f -name '*.log' ``` Все файлы (не каталоги) с расширением .log от текущего каталога ```bash find /var/log -type f -mtime -1 -size +1M ``` Логи изменённые за сутки и больше 1 МиБ - что недавно вспухло ```bash find . -name '*.tmp' -delete ``` Чистка по маске; -delete - встроенное действие, не нужен -exec ```bash find . -type f -print0 | xargs -0 grep -l 'TODO' ``` Безопасно с пробелами в именах: ищем файлы где встречается TODO ```bash find . -type f -perm -4000 ``` SUID-файлы - security-аудит (см. [[file-permissions]]) ```bash find . -type d -empty -delete ``` Удалить пустые каталоги (рекурсивно, снизу вверх) ## См. также - [grep - поиск строк по шаблону](/kb/cmd-grep.md) - [sed - потоковый редактор текста](/kb/cmd-sed.md) - [rsync - инкрементальная синхронизация файлов](/kb/cmd-rsync.md) - [xargs и find -exec - массовые операции](/kb/xargs-and-find-exec.md) - [Inode](/kb/inode.md) - [File permissions: rwx и chmod](/kb/file-permissions.md)