Как устроена строка поиска
Команда find просматривает указанный каталог и все вложенные в него, а для каждого найденного объекта проверяет набор условий. Если объект подошёл под все условия, find выполняет действие. Когда действие не указано, по умолчанию имя просто печатается на экран. Порядок записи такой: сначала путь, где искать, затем условия, затем действие. Путь лучше указывать явно, даже если это текущая папка: точка означает «здесь», и такая запись работает и в Linux, и в macOS.
Условия по умолчанию соединяются как «и»: файл должен подойти под каждое. Для «или» есть ключ -o, а для отрицания знак ! или ключ -not. Скобки для группировки приходится экранировать обратной косой чертой, потому что оболочка иначе примет их за свой синтаксис.
Чтобы не рисковать данными, потренируйтесь на тестовой папке. Создайте её в домашнем каталоге, положите туда пару файлов с разными расширениями и работайте только в ней:
- mkdir -p ~/find-test/docs и touch ~/find-test/a.txt ~/find-test/docs/B.TXT ~/find-test/notes.log;
- find ~/find-test — выведет всё содержимое папки;
- find ~/find-test -type f — только файлы, без каталогов.
Такой первый запуск показывает, как выглядит полный список, и дальше любые условия вы будете сравнивать с ним.
Имя и тип: -name, -iname, -type
Ключ -name сравнивает имя файла с шаблоном и учитывает регистр. Шаблон нужно брать в кавычки: если его не закавычить и в текущей папке найдутся подходящие файлы, оболочка раскроет звёздочку ещё до запуска find, и поиск пойдёт по неожиданному списку. Ключ -iname работает так же, но регистр не различает, поэтому find ~/find-test -iname '*.txt' найдёт и a.txt, и B.TXT, а с -name найдётся только первый.
Шаблон сопоставляется с именем без пути. Если нужно сопоставлять весь путь, используют -path, но это уже отдельный приём, подробности есть в справке команды.
| Условие | Что проверяет |
|---|---|
| -name 'шаблон' | имя по шаблону, регистр важен |
| -iname 'шаблон' | имя по шаблону без учёта регистра |
| -type f | обычные файлы |
| -type d | каталоги |
| -type l | символические ссылки |
| -empty | пустые файлы и пустые каталоги |
Если в выводе много строк «Permission denied», это find натолкнулся на каталоги без прав чтения. Сам поиск продолжается, а сообщения идут в поток ошибок, поэтому их можно скрыть: добавьте в конец 2>/dev/null. Но делайте это осознанно: вместе с шумом скроются и другие ошибки.
Дата и размер: -mtime, -mmin, -newer, -size
Возраст файла в find считается от времени последнего изменения содержимого. Ключ -mtime работает сутками: -mtime -7 означает «изменён менее семи суток назад», -mtime +30 — «изменён более тридцати суток назад», а -mtime 0 — за последние сутки. Дробные части find округляет, и это сбивает с толку: «+1» не означает «старше 24 часов» в бытовом смысле, а означает «двое суток и больше» по правилам округления. Для точных границ удобнее ключ -mmin, он считает минуты.
Ещё один способ — сравнение с эталонным файлом: find . -newer marker.txt покажет всё, что менялось позже файла marker.txt. Эталон можно создать командой touch в нужный момент, а затем искать всё, что появилось после него.
С размером работает -size. После числа ставится суффикс: k для килобайт, M для мегабайт, G для гигабайт (в справке своей системы проверьте точные правила). Плюс означает «больше», минус — «меньше»:
- find ~ -type f -size +100M — файлы крупнее ста мегабайт;
- find ~/find-test -type f -empty — пустые файлы (запись -size -1k тоже подойдёт только для пустых: размер округляется вверх до целых единиц, поэтому «меньше 1k» означает ноль байт);
- find ~/Downloads -type f -mtime +90 — давно не менявшиеся загрузки.
Без суффикса размер считается блоками, а не байтами, и это тоже частая причина странных результатов. Чтобы увидеть, что именно нашлось, добавьте к поиску вывод подробностей через ls -l, как показано в следующем разделе.
Действия: -exec, -print0 и осторожность с -delete
Найти файл — половина дела, обычно с ним что-то нужно сделать. Ключ -exec запускает команду для каждого результата. Место подстановки имени обозначается парой фигурных скобок, а команда заканчивается экранированной точкой с запятой. Пример на тестовой папке: find ~/find-test -name '*.log' -exec ls -l {} \; покажет подробности по каждому логу. Если завершить команду знаком плюс вместо точки с запятой, find соберёт имена в пачки и вызовет команду реже.
Для передачи имён другой программе через конвейер безопаснее пара -print0 и xargs -0: имена разделяются нулевым байтом, поэтому пробелы и переводы строк в именах не ломают разбор. Подробнее о xargs в соседней статье из связанных ниже.
Ключ -delete удаляет найденное сразу и без корзины. Он есть и в GNU find, и в версии для macOS, но порядок условий важен: если поставить его раньше условий, он может удалить больше, чем вы рассчитывали. Поэтому действуйте в три шага:
- Запустите поиск без действия и прочитайте весь список.
- Замените вывод на ls -l через -exec и проверьте размеры и даты.
- Только после этого добавляйте -delete и запускайте на тестовой папке, а на реальных данных — лишь убедившись в резервной копии.
Если удаление нужно не всем найденным файлам, лучше сохранить список в файл через tee и просмотреть его отдельно.
Если find ведёт себя не так, как ожидали
Часть различий между Linux и macOS обусловлена тем, что в большинстве дистрибутивов Linux установлена GNU-версия, а в macOS — BSD-версия. Базовые ключи из этой статьи одинаковы, но отдельные расширения есть только в одной из реализаций, поэтому при сомнении смотрите man find в своей системе.
| Симптом | Вероятная причина | Что проверить |
|---|---|---|
| Ничего не найдено, хотя файл есть | шаблон без кавычек или другой регистр | заключить шаблон в кавычки, попробовать -iname |
| Список неожиданно короткий | поиск начат не с той папки | вывести путь командой pwd или указать абсолютный путь |
| Много строк Permission denied | нет прав на часть каталогов | повторить для своей папки либо скрыть ошибки |
| Нашлись лишние файлы | условия соединены не так, как задумано | добавить скобки с экранированием |
| В GNU find предупреждение про порядок опций | ключ глубины стоит после условий | поставить -maxdepth сразу после пути |
Ограничить глубину можно ключом -maxdepth: find . -maxdepth 1 -type f покажет файлы только в текущей папке. Также учтите, что find просматривает каталоги прямо на диске и не использует индекс, поэтому на очень больших деревьях поиск может занять заметное время. Сузить область поможет более точный стартовый путь.
Если задача состоит в том, чтобы найти крупные папки, а не отдельные файлы, пригодится du, о нём рассказано в материале про большие папки на Mac.