find обходит дерево каталогов и для каждого файла проверяет условия, которые ты задал. Подходящие файлы печатает или передаёт команде. В отличие от ls и масок оболочки, find спускается во все подкаталоги и умеет выбирать по любым свойствам файла.
Синтаксис
find [-H|-L|-P] [где искать…] [опции обхода] [условия] [действие]
Если путь не указан, ищет в текущем каталоге. Условия читаются слева направо и по умолчанию соединяются через «и». Без действия find просто печатает пути (-print).
Опции обхода
| Опция | Что делает |
|---|
-maxdepth N | не спускаться глубже N уровней (0 — только сами стартовые пути, 1 — их содержимое) |
-mindepth N | не проверять файлы ближе N уровней (-mindepth 1 исключает сам стартовый каталог) |
-xdev | не переходить на другие файловые системы (/proc, смонтированные тома) |
-depth | сначала содержимое каталога, потом сам каталог |
-P / -L / -H | ссылки не разыменовывать (по умолчанию) / разыменовывать все / только указанные в командной строке |
-regextype posix-extended | синтаксис регулярных выражений для -regex |
-maxdepth, -mindepth, -xdev, -depth действуют на всё выражение, где бы ни стояли. Пиши их сразу после пути — так читается однозначно.
Условия: имя и путь
| Условие | Что значит |
|---|
-name 'шаблон' | имя файла (без каталога) по шаблону оболочки: *, ?, [abc]; -iname — без учёта регистра |
-path 'шаблон' | весь путь, как его печатает find, например './src/*/test/*'; -ipath — без учёта регистра |
-regex 'выражение' | регулярное выражение по всему пути; -iregex — без учёта регистра |
-lname 'шаблон' | символическая ссылка, указывающая на путь по шаблону |
Условия: тип файла
| Условие | Что значит |
|---|
-type f / d / l | обычный файл / каталог / символическая ссылка |
-type p / s / b / c | именованный канал / сокет / блочное / символьное устройство |
-type f,d | любой из перечисленных типов (GNU) |
-xtype l | ссылка, цель которой не существует («висячая») |
-empty | пустой файл или пустой каталог |
Условия: размер и время
| Условие | Что значит |
|---|
-size +10M / -size -1k | больше 10 МиБ / меньше 1 КиБ; единицы c (байты), k, M, G; размер округляется вверх до единицы |
-mtime +7 / -mtime -1 / -mtime 0 | изменён больше 7 полных суток назад / меньше суток назад / в последние 24 часа |
-mmin +30 | изменён больше 30 минут назад; -mmin -5 — в последние 5 минут |
-atime, -amin | то же по времени последнего чтения |
-ctime, -cmin | то же по времени изменения метаданных (права, владелец, переименование) |
-newer файл | изменён позже, чем указанный файл |
-newermt '2024-06-01 12:00' | изменён позже указанной даты; ! -newermt … — не позже |
-daystart | считать сутки от начала сегодняшнего дня, а не от текущего момента (ставь перед -mtime) |
Условия: владелец, права, ссылки
| Условие | Что значит |
|---|
-user имя / -group имя | владелец / группа (можно числом) |
-uid N / -gid N | числовой UID / GID |
-nouser / -nogroup | у файла UID/GID, которого нет в системе |
-perm 644 | права ровно 644 |
-perm -u+x или -perm -0111 | стоят все указанные биты (могут быть и другие) |
-perm /u+s,g+s или -perm /6000 | стоит хотя бы один из указанных битов |
-readable / -writable / -executable | текущий пользователь может читать / писать / запускать |
-links N | число жёстких ссылок; -links +1 — у файла есть другие имена |
-inum N / -samefile файл | по номеру inode / все имена того же файла |
Операторы
| Оператор | Что значит |
|---|
A B или A -a B | «и» (-and) |
A -o B | «или» (-or); у «и» приоритет выше |
! A или -not A | «не» |
\( … \) | группировка; скобки экранируй от оболочки и отделяй пробелами |
Действия
| Действие | Что делает |
|---|
-print | печатает путь (действие по умолчанию) |
-print0 | печатает пути через нулевой байт — пара для xargs -0 |
-printf 'формат' | печатает по шаблону (см. ниже); перевод строки — \n явно |
-ls | подробная строка, как ls -dils |
-fprint файл | пишет пути в файл, а не на экран |
-delete | удаляет найденное; каталоги — только пустые |
-exec команда {} \; | запускает команду для каждого файла; {} — путь |
-exec команда {} + | запускает команду один раз на пачку файлов — быстрее; {} должен стоять последним |
-execdir команда {} \; | то же, но запускает в каталоге найденного файла |
-ok команда {} \; | как -exec, но спрашивает подтверждение на каждый файл |
-prune | не спускаться в этот каталог |
-quit | остановиться сразу после первого совпадения |
-exec … \; работает и как условие: истинно, если команда вернула 0. Так можно фильтровать любой проверкой: -exec grep -q текст {} \; -print.
Формат -printf и -ls
| Директива | Что выводит |
|---|
%p / %P | путь / путь без стартового каталога |
%f / %h | имя файла / каталог, в котором он лежит |
%s / %k | размер в байтах / занятое место в КиБ |
%m / %M | права числом (644) / буквами (-rw-r--r--) |
%u / %g | владелец / группа |
%TY-%Tm-%Td %TH:%TM | дата изменения по частям; %t — целиком, %T@ — секунды с 1970 года |
%y / %d / %n | тип (f, d, l) / глубина / число жёстких ссылок |
%l | куда указывает символическая ссылка |
Строка -ls: номер inode, занятое место в КиБ, права, число ссылок, владелец, группа, размер в байтах, дата изменения, путь.
Примеры
# все .conf в /etc, только обычные файлы
find /etc -type f -name '*.conf'
# файлы больше 100 МиБ на корневой ФС, ошибки доступа — в /dev/null
find / -xdev -type f -size +100M 2>/dev/null
# логи старше 7 суток
find /var/log -name '*.log' -mtime +7
# изменённые за последние 30 минут
find ~/project -type f -mmin -30
# изменённые в заданном промежутке дат
find /srv/app -newermt '2024-01-01' ! -newermt '2024-02-01'
# пустые каталоги в текущем каталоге, без спуска внутрь вложенных
find . -maxdepth 1 -type d -empty
# .log ИЛИ .tmp — группировку скобками экранируй от оболочки
find . \( -name '*.log' -o -name '*.tmp' \) -type f
# не заходить в node_modules и .git
find . \( -name node_modules -o -name .git \) -prune -o -type f -print
# файлы с setuid-битом во всей системе
find / -xdev -type f -perm -4000 2>/dev/null
# файлы, у владельца которых нет учётной записи
find /home -nouser
# размер, права и имя в своём формате, крупные файлы сверху
find /var/log -type f -printf '%s\t%m\t%p\n' | sort -rn | head
# посчитать строки во всех .py одним вызовом wc
find . -name '*.py' -exec wc -l {} +
# оставить только файлы, в которых есть строка
find /etc -name '*.conf' -exec grep -q 'include' {} \; -print
# безопасно передать имена с пробелами в xargs
find . -name '*.bak' -print0 | xargs -0 rm --
# удалить старые временные файлы (сначала проверь без -delete)
find /tmp -type f -name '*.tmp' -mtime +3 -delete
# первое совпадение — и хватит
find / -name 'nginx.conf' -print -quit 2>/dev/null
Подводные камни
- Шаблон без кавычек раскроет оболочка до запуска
find. find . -name *.log при одном .log-файле в текущем каталоге превратится в -name app.log и найдёт только файлы с этим именем, а при нескольких — сломается («paths must precede expression»), если их несколько. Всегда бери шаблон в кавычки.
-name смотрит только на имя. -name 'src/*.js' никогда не совпадёт — для пути есть -path. А -regex, наоборот, сравнивается со всем путём: -regex '.*\.log', а не -regex '\.log'.
-mtime +7 — это «больше 7 полных суток», то есть фактически 8 и больше: дробная часть отбрасывается. -mtime 7 — от 7 до 8 суток назад.
- Размер округляется вверх.
-size -1M находит только пустые файлы: файл в 1 байт уже считается «1 мегабайтом». Для точных порогов используй c (байты) или k.
- Порядок важен.
-delete в начале выражения удалит всё подряд, до проверки остальных условий. Сначала запусти без -delete и посмотри список.
-delete и -prune несовместимы: -delete включает -depth, при котором -prune не работает, и find откажется запускаться. Непустые каталоги -delete не удаляет («Directory not empty»).
-o без скобок. find . -name '*.log' -o -name '*.tmp' -print напечатает только .tmp: -print привязан ко второй половине. Бери «или» в \( … \).
-exec … {} +: {} должен стоять прямо перед +, иначе «missing argument to `-exec'».
- Код возврата. «Ничего не найдено» — это успех (код 0). Ненулевой код означает ошибки: нет каталога, нет доступа. Проверяй вывод, а не код.
- Имена с пробелами и переводами строк ломают
find … | xargs. Используй -print0 с xargs -0 или -exec … {} +.
См. также
xargs · ls · stat · chmod · grep · tar · df-du