open atlas
↑ К треку
Командная строка CLI · 04 · 02

Поиск файлов командой find

find обходит дерево каталогов и ищет файлы по имени, типу, размеру или времени изменения. -exec запускает команду для каждого результата; -print0 с xargs -0 безопасно обрабатывает имена файлов с пробелами.

CLI Junior ◷ 22 min
Уровень
ОсновыJuniorMiddleSenior

Глобы ищут только в текущем каталоге. Когда нужно охотиться по всему дереву каталогов — найти все .log-файлы под /var, все файлы больше 100 МБ или все файлы, изменённые за последние 24 часа — нужен find. Он рекурсивно обходит дерево, фильтрует по почти любому атрибуту файла и может выполнять команду для каждого совпадения.

К концу урока ты будешь писать команды find с фильтрацией по имени, типу, размеру и времени изменения, а также безопасно выполнять действия над результатами.

Цель

После этого урока ты сможешь использовать find для поиска в дереве каталогов по имени (-name), типу (-type), размеру (-size) и времени изменения (-mtime); выполнять команду для каждого результата с -exec; и безопасно обрабатывать имена файлов с пробелами через -print0 и xargs -0.

1

Базовый синтаксис: find <путь> <выражение>. Первый аргумент — корень поиска; всё остальное — предикаты. Без предикатов find выводит каждый найденный файл:

find /var/log          # список всех файлов под /var/log рекурсивно
find .                 # список всех файлов в текущем каталоге

Предикаты вычисляются слева направо и объединяются неявным И. Добавь -maxdepth N, чтобы ограничить глубину рекурсии.

2

-name и -iname фильтруют по имени файла. Шаблон использует glob оболочки, но должен быть взят в кавычки, чтобы оболочка не раскрыла его до того, как find его увидит:

find . -name "*.log"           # файлы, оканчивающиеся на .log
find /etc -name "nginx.conf"   # поиск точного имени
find . -iname "readme*"        # без учёта регистра; находит README.md, readme.txt

-name сопоставляется только с именем файла, не с полным путём. Для сопоставления с путём используй -path "*/dir/*.log".

3

-type фильтрует по типу записи. Распространённые значения:

ФлагЗначение
-type fобычный файл
-type dкаталог
-type lсимволическая ссылка
find . -type f -name "*.sh"    # только файлы, не каталоги с именем *.sh
find /tmp -type d              # список всех каталогов под /tmp

Сочетание -type f с -name — наиболее распространённый шаблон.

4

-size фильтрует по размеру файла. Суффиксы: c (байты), k (кибибайты), M (мебибайты), G (гибибайты). Используй + для «больше» и - для «меньше»:

find /var/log -size +10M        # файлы больше 10 МиБ
find . -size -1k                # файлы меньше 1 КиБ
find /home -type f -size +100M  # большие файлы, занимающие место

-mtime N фильтрует по времени изменения в днях. +N означает «старше N дней»; -N означает «изменён в течение последних N дней»:

find . -mtime -1    # изменены за последние 24 часа
find . -mtime +30   # не изменялись более 30 дней
find . -mmin -60    # изменены в течение последних 60 минут (-mmin в минутах)
5

-exec запускает команду для каждого совпадения. Заполнитель {} заменяется именем найденного файла. Выражение должно заканчиваться на \; (один вызов на файл) или + (все файлы в одном вызове):

# Удалить каждый .tmp файл (один вызов rm на файл)
find . -name "*.tmp" -exec rm {} \;

# Удалить каждый .tmp файл (один вызов rm со всеми файлами — быстрее)
find . -name "*.tmp" -exec rm {} +

# Вывести размер каждого файла больше 10M
find /var -size +10M -exec du -sh {} \;

-print0 с xargs -0 — самая безопасная альтернатива, когда имена файлов могут содержать пробелы или переносы строк:

find . -name "*.log" -print0 | xargs -0 gzip

-print0 разделяет результаты нулевым байтом вместо переноса строки; xargs -0 читает разделённый нулями ввод. Это выживает при именах вроде мой файл.log.

Разбор примера

Поиск и сжатие старых логов.

На сервере под /var/log/app накапливаются логи. Нужно сжать каждый .log-файл, не изменявшийся 7 и более дней:

find /var/log/app -type f -name "*.log" -mtime +7 -print0 \
  | xargs -0 gzip --best

Разбор:

  • -type f — только обычные файлы, пропуская каталоги
  • -name "*.log" — только лог-файлы (шаблон в кавычках, чтобы оболочка не раскрыла его)
  • -mtime +7 — старше 7 дней
  • -print0 | xargs -0 gzip --best — передаёт все совпадения в gzip одной пакетной операцией, с нулевым разделителем для безопасности
# Проверка: список всех сжатых файлов, созданных сегодня
find /var/log/app -name "*.gz" -mtime -1
Почему это работает

BSD find на macOS отличается от GNU find на Linux. Ключевые отличия:

  • -mtime: GNU округляет до ближайшей 24-часовой границы; BSD строго 24 часа × N.
  • -exec {} + (пакетный режим) — расширение GNU; BSD find на macOS его не поддерживает. Для кроссплатформенных скриптов используй -print0 | xargs -0.
  • GNU find поддерживает -printf для форматированного вывода; BSD — нет. Используй stat как обходной путь на macOS.

Если пишешь скрипты для обеих платформ, тестируй на macOS явно или используй gfind (GNU findutils через Homebrew).

Частая ошибка

Забыть взять шаблон -name в кавычки. Если в текущем каталоге есть файл, совпадающий с глобом, оболочка раскроет его до того, как find увидит аргумент -name:

# Представь, что в текущем каталоге есть error.log
find /var/log -name *.log    # оболочка раскрывает в: find /var/log -name error.log

Теперь find ищет только файл с именем error.log, а не все .log-файлы. Этот баг непостоянен и сложно заметить. Всегда бери в кавычки аргументы -name и -path: find /var/log -name "*.log".

Проверь себя
Викторина

Какая команда find удаляет все .tmp-файлы под /tmp, безопасно обрабатывая имена файлов с пробелами?

Итог

find <путь> <предикаты> обходит дерево каталогов и выводит (или обрабатывает) каждую запись, соответствующую всем предикатам. Ключевые предикаты: -name (glob имени файла — всегда брать в кавычки), -type f/d/l (тип записи), -size +N/-N (размер файла), -mtime +N/-N (время изменения в днях). -exec команда {} \; запускает команду для каждого файла; -exec команда {} + объединяет все совпадения в один вызов (быстрее, но недоступно в BSD find). -print0 | xargs -0 — самый безопасный конвейер при именах файлов с пробелами.

Практика

Начни сверху. Задачи идут от простого к сложному: вспомнить факт, применить к случаю, затем senior-уровень. Открой, попробуй, потом открой ответ.

вспомнитьприменитьуглубить0 из 4 завершено

Что-то непонятно?

Задай вопрос по этому уроку. Вопросы анонимны и попадают напрямую автору — урок станет лучше.

хоткеи развернуть
поиск
K
пред. пьеса
k
след. пьеса
j
тиры
t
это меню
?
sources3
expand
  1. 01
  2. 02
  3. 03

Trademarks belong to their respective owners. Editorial reference only.