Linux: как найти файл командой find и чем её заменить

Потеря файла в Linux — ситуация неприятная, но почти всегда решаемая. Если вы помните хотя бы часть имени, примерную дату создания или размер, поиск из терминала займёт секунды. Главное — знать правильные ключи и понимать, чем отличаются инструменты, которые на первый взгляд делают одно и то же.
Графические файловые менеджеры опираются на заранее построенный индекс и часто пасуют перед сетевыми шарами, съёмными дисками и каталогами, куда индексатор не имеет доступа. find ведёт себя иначе: он честно обходит дерево каталогов через системные вызовы ядра, поэтому находит объекты даже там, где никакого индекса нет в принципе. Плата за это — время: на домашнем каталоге с миллионом файлов обход может занять десятки секунд. Зато locate ответит мгновенно — но только про то, что успело попасть в его базу.
Второе достоинство find — условия. Имя, тип, размер, дата изменения, права доступа, владелец, inode, глубина вложенности: всё это комбинируется логическими операторами, а полученная выборка сразу передаётся на удаление, архивацию или обработку. Именно поэтому find живёт в скриптах, cron-задачах и бэкапных обвязках чаще, чем любой другой инструмент поиска.
Общая схема синтаксиса проста: find [где искать] [условия] [действие]. Если не указать ничего, find честно найдёт всё подряд, включая каталоги, симлинки и спецфайлы устройств. Вот несколько рабочих примеров, которые стоит помнить наизусть:
- find . -type f -name '*.log' — все обычные файлы .log начиная с текущего каталога.
- find /var -maxdepth 2 -type f -iname '*.log' — то же, но без учёта регистра и с ограничением глубины в два уровня.
- find /home -type f -size +500M -mtime -3 — файлы крупнее 500 МБ, изменённые за последние три дня.
- find /var/www -type f -perm -o+w — файлы, доступные на запись всем пользователям сразу.
Конструкция 2>/dev/null здесь не случайна: обход корня почти всегда упирается в /proc, чужие точки монтирования и закрытые каталоги, а поток сообщений «Permission denied» забивает полезный вывод. Флаг -xdev решает ту же проблему иначе — он запрещает выходить за пределы текущей файловой системы, что особенно полезно при поиске на сервере с примонтированными NFS-шарами.
Условий у find несколько десятков, но в ежедневной работе хватает полутора десятков. -name и -iname ищут по шаблону имени (второй игнорирует регистр), -type фильтрует по типу объекта (f — файл, d — каталог, l — симлинк), -size задаёт размер (+100M, -1k, точное значение без знака), -mtime и -mmin — время изменения в сутках или минутах. Флаг -newer отбирает файлы, изменённые позже указанного эталона, -perm работает с правами доступа, -user и -group — с владельцем и группой, -maxdepth ограничивает глубину обхода, а -empty находит пустые файлы и каталоги.
Логика комбинирования простая: несколько условий подряд означают И, -o — ИЛИ, ! или -not — отрицание. Скобки обязательно экранируются, иначе оболочка попытается раскрыть их сама и передаст find мусор. Например, картинки .jpg или .png старше 180 дней ищутся так: find /srv/photos -type f ( -iname '*.jpg' -o -iname '*.png' ) -mtime +180.
Абсолютного победителя среди инструментов нет. Практика такая: locate — чтобы за секунду вспомнить, куда вы положили файл полгода назад; fd — для повседневных задач вроде «показать все .go файлы в проекте» (он по умолчанию игнорирует .git и node_modules, а обход ведёт в несколько потоков); find — когда нужны сложные условия, cron или переносимый скрипт, работающий на любой машине без доустановки пакетов. grep -r и ripgrep подключаются, когда искать надо не имя, а текст внутри файлов. which и whereis мгновенно отвечают на вопрос, установлен ли бинарник в PATH.
Найденные файлы почти всегда нужно с чем-то сделать. У find есть собственное действие -exec, и тут важно понимать разницу между завершением ; и +: в первом случае команда запускается отдельно на каждый файл, во втором — одной жирной порцией на всю выборку, что экономит секунды и ресурсы. Связка -print0 | xargs -0 надёжнее простого конвейера с xargs, когда в именах встречаются пробелы и переносы строк.
И главное правило безопасности: никогда не запускайте find с -delete или -exec rm по широкому шаблону вроде '*', не посмотрев сначала список. Схема простая — выполните find . -name '*.bak' -print, убедитесь, что выборка та самая, и только потом меняйте -print на -delete. Одна лишняя секунда проверки дешевле восстановления файлов из бэкапа.
Типичные ошибки, которые допускают даже опытные администраторы, сводятся к нескольким пунктам. Указывайте стартовый каталог явно — без аргумента find берёт текущий, и скрипт, запущенный из домашнего каталога, внезапно обойдёт пол-диска. Гасите stderr через 2>/dev/null или -xdev. Следите за порядком условий: find обрабатывает их слева направо, и с -o и скобками легко получить выборку не той ширины, чем ожидалось. Помните, что индекс locate устаревает — база обновляется через updatedb, обычно по расписанию, а лишние каталоги исключаются в /etc/updatedb.conf. И щадите продакшен: на нагруженном сервере запускайте тяжёлый обход через nice -n 19 ionice -c3 find / ..., чтобы не поднять load average.
Выучите десяток ключей вроде -type, -name, -mtime и -size, добавьте привычку сначала смотреть вывод через -print — и поиск файлов в Linux перестанет быть лотереей. Find есть везде и ведёт себя одинаково, а это в мире, где серверы живут годами без переустановки, стоит дороже любой скорости.


