Как найти файл и текст в Linux: find и grep

Linux Автор: Среда и версия: Ubuntu 24.04, GNU findutils 4.9, GNU grep 3.11
содержание

Поиск в Linux — это два разных вопроса. «Где лежит файл с таким именем?» — это find, он обходит дерево каталогов и смотрит на имена и свойства. «В каком файле встречается этот текст?» — это grep, он читает содержимое и печатает совпавшие строки. Путать их — значит искать не тем инструментом. Примеры ниже выполнены на дереве из двух каталогов: app/ с кодом и logs/ с логами.

Linux / 01

find отбирает имена. grep — строки внутри

find отбирает имена. grep — строки внутри01 find / файлы *.log app.log · error.log access.log main.py не подходит по имени. 02 grep / содержимое ERROR → совпало error → нет В app.log найдутся строки с ERROR. Для любого регистра нужен -i.01find / файлы*.logapp.log · error.logaccess.logmain.py не подходит по имени.02grep / содержимоеERROR → совпалоerror → нетВ app.log найдутся строки с ERROR. Длялюбого регистра нужен -i.
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 из одиночных команд в связки.

Источники