Поиск в Linux — это два разных вопроса. «Где лежит файл с таким именем?» — это find, он обходит дерево каталогов и смотрит на имена и свойства. «В каком файле встречается этот текст?» — это grep, он читает содержимое и печатает совпавшие строки. Путать их — значит искать не тем инструментом. Примеры ниже выполнены на дереве из двух каталогов: app/ с кодом и logs/ с логами.
find отбирает имена. grep — строки внутри
find отвечает «какие файлы», grep — «какие строки». Нижний регистр error без флага -i в выдачу не попадает.find: где лежит файл
Первый аргумент — откуда искать, дальше условия. Точка — текущий каталог:
find . -name "*.log"
./logs/old/app-2025.log
./logs/app.log
./logs/error.log
find обошёл всё дерево, включая вложенный logs/old/. Маску обязательно брать в кавычки — почему, разобрано в ошибках ниже. Регистр в -name важен: APP.LOG и app.log — разные имена. Если регистр неизвестен, есть -iname:
find . -iname "APP.LOG"
./logs/app.log
Условие -type отбирает по виду записи: f — файлы, d — каталоги:
find . -type d
.
./app
./logs
./logs/old
Условий больше: -mtime -1 находит изменённое за последние сутки, -size +100M — файлы больше ста мегабайт. Условия комбинируются простым перечислением: find . -type f -name "*.py".
find -exec: сделать что-то с найденным
Найденные файлы можно сразу передать другой команде. {} — место подстановки, + в конце собирает все находки в один вызов:
find . -name "*.log" -exec wc -l {} +
1 ./logs/old/app-2025.log
4 ./logs/app.log
1 ./logs/error.log
6 total
Одной строкой: найти все логи и посчитать в них строки. Тот же приём удаляет мусор (-exec rm {} +) — но сначала стоит запустить find без -exec и глазами проверить список.
grep: в каком файле текст
grep печатает строки файла, где встретился образец. Флаг -n добавляет номера строк:
grep -n "ERROR" logs/app.log
2:10:13 ERROR нет доступа к базе
В файле есть ещё строка с error в нижнем регистре, и она не нашлась: grep по умолчанию чувствителен к регистру. Флаг -i снимает это:
grep -in "error" logs/app.log
2:10:13 ERROR нет доступа к базе
4:10:15 error timeout
Ещё два флага на каждый день: -v инвертирует условие и оставляет строки без образца, -c печатает только счётчик совпадений:
grep -c "INFO" logs/app.log
2
Поиск по всему проекту: grep -r
Каталог grep сам не обходит — нужен флаг -r, рекурсивный поиск:
grep -rn "ERROR" logs/
logs/app.log:2:10:13 ERROR нет доступа к базе
logs/error.log:1:10:13 ERROR диск переполнен
К номеру строки добавилось имя файла. Когда нужны только имена файлов, а не сами строки, есть -l:
grep -rl "TODO" app/
app/main.py
Так ищут все файлы проекта с пометками TODO. Шумные каталоги исключаются флагом --exclude-dir:
grep -rn --exclude-dir=old "INFO" logs/
logs/app.log:1:10:12 INFO запуск сервера
logs/app.log:3:10:14 INFO повторное подключение
Без него в выдачу попал бы и архивный logs/old/. В репозиториях так прячут .git и node_modules.
Ошибки, на которых спотыкаются
Маска без кавычек. Если в текущем каталоге лежит main.log, то find . -name *.log превратится в find . -name main.log: шелл раскроет звёздочку до запуска find, и поиск найдёт один файл вместо всех. С кавычками маска доходит до find нетронутой. Это самая частая и самая незаметная ошибка с find.
grep на каталог без -r. grep "ERROR" logs отвечает grep: logs: Is a directory и не ищет ничего.
Забытый -i. Логи пишут и ERROR, и error. Поиск без -i молча теряет часть строк — выдача выглядит правдоподобно, и пропажу легко не заметить.
find без стартового пути. Привычка писать find -name ... работает в GNU find, но путь лучше указывать явно: find . -name ... читается однозначно и переносится на другие системы.
Частые вопросы
Как найти файл по имени во всей системе
find / -name "config.yaml" 2>/dev/null. Поиск от корня упирается в каталоги, куда нет доступа, и сыплет ошибками Permission denied — хвост 2>/dev/null их прячет. Как устроено это перенаправление, разобрано в статье про конвейеры.
Как найти текст сразу во всех файлах проекта
grep -rn "текст" . — рекурсивно от текущего каталога, с именами файлов и номерами строк. В большом репозитории добавь --exclude-dir=.git --exclude-dir=node_modules, иначе выдачу зальёт служебными совпадениями.
Чем find отличается от grep
find смотрит на файл снаружи: имя, тип, размер, дата. grep — внутрь: какие строки содержат образец. Их сила в связке: find отбирает файлы, grep ищет в отобранном.
Как найти и удалить файлы одной командой
find . -name "*.tmp" -exec rm {} +. Правило безопасности то же, что у rm из базовых команд: сначала тот же find без -exec, глазами проверить список, потом удалять.
Где потренироваться
Вопросы на find, grep и маски есть в скилл-тесте по Linux — 8 вопросов с мгновенной оценкой. Дальше по справочнику — конвейеры и перенаправление: именно они превращают find и grep из одиночных команд в связки.