notby.NET Logo

Поиск внутри файлов в Linux / FreeBSD (утилита grep)

При работе бывает возникает необходимость находить текст внутри файлов, будь то для анализа логов, чтения конфигурационных файлов или поиска переменной внутри файлов сайта или приложения. В операционных системах Linux или FreeBSD для этой задачи доступно несколько утилит, одной из самых популярных среди них является утилита grep. Она предназначена для поиска текста внутри файлов на основе регулярных выражений или фильтрации вывода команд.

В операционной системе FreeBSD и большинстве дистрибутивов Linux утилита grep уже установлена по умолчанию.

1. Синтаксис утилиты grep

Основной синтаксис утилиты grep выглядит следующим образом:

grep [опции] шаблон [путь к файлу или каталогу]
  • опции — список дополнительных параметров, позволяющих настраивать процесс поиска и вывод найденных данных;
  • шаблон — строка или регулярное выражение, на основе которого необходимо осуществить поиск;
  • путь к файлу или каталогу — в каком месте будет выполнятся поиск, например, в конкретном файле, в целом каталоге во всех файлах или во всех подкаталогах.

По умолчанию шаблон воспринимается как базовое регулярное выражение. Если в шаблоне будут содержатся специальные символы ^ . [ ] * $, то результат может дать неожиданный результат или вовсе завершится ошибкой. Чтобы отключить регулярное выражение и рассматривать искомый шаблон как текст, необходимо использовать -F опцию.

2. Основные опции и параметры

Список всех доступных опций утилиты grep можно посмотреть, используя команду:

grep --help

Описывать все опции я не буду, а покажу только основные и часто используемые, которые могут пригодится. В дальнейшем часть из них будет показана в примерах.

Основные опции утилиты grep:

  • -r — Рекурсивный поиск в каталоге и всех подкаталогах;
  • -R — Рекурсивный поиск в каталоге и всех подкаталогах включая ссылки;
  • -E — Использовать расширенные регулярные выражения;
  • -P — Использовать регулярные выражения Perl (PCRE);
  • -F — Рассматривать шаблон как строку, а не регулярное выражение;
  • -i —  Игнорировать регистр (поиск не учитывает заглавные и строчные буквы);
  • -w — Искать как слово разделенное пробелами или знаками препинания;
  • -s — Не показывать ошибки доступа к файлам и каталогам;
  • -I —  Игнорировать двоичные файлы (i большая);
  • -l — Выводить только имена файлов, в которых найден шаблон (L маленькая);
  • -n — Выводить номера строк, в которых найден шаблон;
  • -v — Инвертировать поиск (выводить строки, не содержащие шаблон);
  • -c — Подсчитывать количество строк, соответствующих шаблону;
  • -A[N] — Показать количество N строк после совпадения;
  • -B[N] — Показать количество N строк до совпадения;
  • -C[N] — Показать количество N строк до и после совпадения;
  • --color — Подсветка найденных совпадений для удобства восприятия.

Опции можно указывать отдельно, каждую со своим дефисом:

grep -n -F -i 'Tommy Wirser' user.db

Или объединить под общий дефис:

grep -nFi 'Tommy Wirser' user.db

3. Шаблон поиска в одинарные или двойные кавычки

Шаблон можно заключать как в 'одинарные', так и в "двойные кавычки". Если использовать “двойные кавычки”, то например при поиске переменных внутри PHP-скрипта будет неожиданный результат.

Создаем в качестве примера файл config.php следующего содержимого:

<?php
$site_url = 'https://notby.net';
$site_name = 'notby.NET';
$site_admin = 'Tommy Wirser';
?>

Выполняем поиск переменной $site_name и ожидаем вывод строки с этой переменной…

grep "$site_name" config.php
Выполнена команда поиска “grep "$site_name" config.php” (шаблон заключен в двойные кавычки) в консоли Debian, и в результате выведены все строчки файла config.php

В результате были выведены все строки файла. Но ведь запрос был конкретный…

Это произошло из-за того что командная оболочка (sh, bash, zsh, …) операционной системы считала значение переменной $site_name внутри себя, но такая переменная не существует и поэтому было возращено пустое значение.

Запрос выше был аналогичен следующему запросу

grep "" config.php

Чтобы командная оболочка не искала в строке переменную, необходимо использовать 'одинарные кавычки'

grep '$site_name' config.php
Выполнена команда поиска “grep '$site_name' config.php” (шаблон заключен в одинарные кавычки) в консоли Debian, и в результате выведены найденные строчки

В результате была найдена строка, которая содержит $site_name переменную.

Выполним запрос с использованием "двойных кавычек" на поиск в файле /etc/passwd всех пользователей, которые используют ту же программную оболочку

grep "$SHELL" /etc/passwd
В консоли Debian выполнена команда “echo $SHELL” и затем поиск командой “grep "$SHELL" /etc/passwd”. Были выведены строчки пользователей которые используют тужа программную оболочку

Так как переменная $SHELL имеет значение командной оболочки пользователя, то были выведены пользователи которые используют по умолчанию туже оболочку.

4. Примеры использования утилиты grep

4.1. Поиск текста внутри файла

Найдем строку, которая содержит последовательность букв error_reporting внутри файла /etc/php/fpm/php.ini, чтобы посмотреть о каких ошибках PHP сообщает

grep 'error_reporting' /etc/php/php.ini
Выполнена команда поиска “grep "error_reporting" /etc/php/php.ini” в консоли Debian, и в результате выведена строка: error_reporting = E_ALL

Были найдены две строки, которые содержат значение error_reporting и как можно видеть значение у переменной установлено E_ALL.


Запустим аналогичный поиск с указанием опции -n, для того чтобы вывести номера найденных строк в файле

grep -n 'error_reporting' /etc/php/php.ini
Выполнена команда поиска “grep -n "error_reporting" /etc/php/php.ini” в консоли Debian, и в результате выведена строка error_reporting = E_ALL и показан ее номер в файле

Перед найденными строками показывается их номер в искомом файле. Открыв файл, будет удобно быстро перейти к нужной строке, зная ее номер.


Если использовать опцию -i, то регистр символов учитывается не будет. Найдем строки, которые содержат MySQL в файле php.ini

grep -i 'MySQL' /etc/php/php.ini
Выполнена команда поиска “grep -i 'MySQL' /etc/php/php.ini” в консоли Debian, и в результате выведена все найденные строки без учета регистра букв

Все строки, содержащие MySQL как маленькими, так и большими буквами, были найдены.


В предыдущем примере можно было заметить, что были найдены строки MySQLi, mysqli.so и так далее, хотя запрос был MySQL. Если необходимо найти конкретное слово которое разделено пробелами или другими знаками, необходимо добавить опцию -w в запрос.

Выполним предыдущий запрос, но с добавлением опции -w

grep -i -w 'MySQL' /etc/php/php.ini
Выполнена команда поиска “grep -i -n 'MySQL' /etc/php/php.ini” в консоли Debian, и в результате выведена все найденные строки содержащие слово MySQL без учета регистра букв

Выведены все строки содержащие слово MySQL без учета регистра букв.


Если необходимо найти все разделы конфигурационного файла php.ini (а они заключены в квадратные скобки) для этого можно выполнить grep '[' /etc/php/php.ini запрос, но он завершится grep: Invalid regular expression ошибкой. Это происходит из-за того что шаблон рассматривается как базовое регулярное выражение и символ [ используется в синтаксисе регулярного выражения.

Выполним поиск с добавлением опции -F, чтобы шаблон воспринимался как обычная строка

grep -F '[' /etc/php/php.ini
Выполнена команда поиска “grep -F '[' /etc/php/php.ini” в консоли Debian, и в результате выведены разделами PHP.ini файла начинающиеся с символа [

Выведены разделы конфигурационного файла php.ini, так как они начинаются с символа квадратной скобки.

4.2. Поиск текста внутри нескольких файлов

Можно искать одновременно один шаблон в нескольких файлах. Для этого их необходимо перечислить через пробел.

Найдем строки, которые содержат root в файлах /etc/passwd и /etc/group

grep 'root' /etc/passwd /etc/group
Выполнена команда поиска “grep 'root' /etc/passwd /etc/group” в консоли Debian, и в результате выведены строки содержащие root в файлах /etc/passwd и /etc/group

В файле /etc/passwd найден пользователь root, а в файле /etc/group найдена его группа.

Еще в качестве примера можно сравнить какие значения установлены в разных конфигурационных файлах. Сравним, какое значение переменной upload_max_filesize установлено в основном файле php.ini с файлом php-upload.ini который используется на сервере загрузки файлов.

grep 'upload_max_filesize' php.ini php-upload.ini
Выполнена команда поиска “grep 'upload_max_filesize' php.ini php-upload.ini” в консоли Debian, и в результате выведены значения параметра upload_max_filesize равно 32М в первом файле и 128М во втором

Аналогично можно использовать для сравнения файлов других программ.

4.3. Поиск во всех файлах внутри каталога и подкаталогов

Например, можно найти внутри каталога /var/log/ в каких логах существуют ошибки. Выполним поиск по слову error в каталоге /var/log/

grep 'error' /var/log/*

* – указывает что необходимо произвести поиск внутри всех файлов каталога.

Выполнена команда поиска “grep 'error' /var/log/*” в консоли Debian, и в результате выведено много предупреждений: Permission denied

При таком поиске были выведены сообщения Permission denied, так как пользователь без root-прав не может получить доступ к определенным файлам журнала событий.

Чтобы не выводить эти сообщения и вывести только найденные строки в файлах к которым имеется доступ, надобно добавить опцию -s

grep -s 'error' /var/log/*
Выполнена команда поиска “grep -s 'error' /var/log/*” в консоли Debian, и в результате выведены строчки с ошибками в файлах /var/log/messages, /var/log/Xorg.1.log, /var/log/Xorg.0.log

Произошел поиск только всех файлов к которым есть доступ внутри каталога /var/log/ без учета подкаталогов.


Чтобы произвести рекурсивный поиск по файлам в каталоге и всех его подкаталогах, необходимо добавить опцию на выбор:

  • -r — рекурсивный поиск по всем подкаталогам без включения ссылок;
  • -R — рекурсивный поиск по всем подкаталогам с включением ссылок.

Выполним поиск из предыдущего примера, но добавим опцию -r

grep -s -r 'error' /var/log/

Символ * в конце пути где искать, уже нет смысла указывать, так как с опцией -r или -R путь воспринимается как каталог.

Выполнена команда поиска “grep -s -r  'error' /var/log/*” в консоли Debian, и в результате выведены строчки с ошибками в файлах /var/log/messages, /var/log/installer/status, /var/log/Xorg.1.log, /var/log/Xorg.0.log

Если в выводе попадутся сообщения binary file matches (двоичный файл совпадает) после пути файла, то эти сообщения означают что данные файлы являются двоичными. Чтобы не выполнять сообщения и искать внутри этих файлов необходимо добавить опцию -I

grep -s -r -I 'error' /var/log/

4.4. Поиск в файлах с определенным расширением

Когда необходимо найди информацию внутри файлов с определенным расширением в одном каталоге, достаточно написать *.расширение в конце пути каталога.

Найдем в каких css-файлах содержатся настройки стиля для тега pre

grep 'pre' /var/www/*.css
Выполнена команда поиска “grep 'pre' /var/www/*.css” в консоли Debian, и в результате выведены строчки со значением pre в файлах /var/www/editor.css, /var/www/notby.net.css

Если необходимо произвести рекурсивный поиск текста внутри файлов с определенным расширением во всех подкаталогах , необходимо использовать опцию --include='*.расширение' для указания расширения файлов.

Найдем в каких PHP-файлах используется константа DB_HOST внутри CMS WordPress, которая находится в каталоге /var/www/wordpress/ и внутри всех подкаталогов

grep -r 'DB_HOST' /var/www/wordpress/ --include='*.php'
Выполнена команда поиска “grep -r 'DB_HOST' /var/www/wordpress/ --include='*.php'” в консоли Debian, и в результате выведены строки со значением DB_HOST в файлах wp-config.php, setup-config.php, load.php, class-wpdb.php в подкаталогах var/www/wordpress/

4.5. Вывод нескольких строк до или после найденной строки

Подобный поиск можно использовать для вывода строк до или после событий warning, error, в журнале ошибок какой-либо программы или операционной системы. Также это полезно, если необходимо получить строки и в дальнейшем их использовать в написанном скрипте.

Например, выполним поиск внутри CSS файла по фразе body и добавим параметр -A5, чтобы вывести 5 строк после найденной строки

grep -A5 'body' notby.net.css
Выполнена команда поиска “grep -A5 'body' notby.net.css” в консоли Debian, и в результате выведены строки содержащие body и 5 строк после

Пяти строк было достаточно для отображения полностью параметров внутри CSS селектора.

Чтобы вывести строки до найденной, необходимо использовать параметр -B с указанием количества строк, а чтобы вывести до и после использовать, параметр -C с указанием количества строк.

4.6. Подсветка найденного шаблона

В некоторых дистрибутивах Linux по умолчанию добавлена подсветка цветом вывода утилиты grep. Если этого не происходит необходимо добавить опцию --color в запрос поиска.

grep --color 'Tommy Wirser' user.db
grep  'Tommy Wirser' user.db --color

С опцией  --color вывод будет выглядеть как на скриншотах в этой статье.

5. Примеры использования регулярных выражений

По умолчанию шаблон воспринимается как базовое регулярное выражение, некоторые символы в нем имеют следующие значение:

  • ^ — Указывает на начало строки. Например, ^start соответствует строке, начинающейся с “start”;
  • $ — Указывает на конец строки. Например, end$ соответствует строке, заканчивающейся на “end”;
  • . — Соответствует любому одиночному символу;
  • * — Соответствует нулю или более повторениям предыдущего символа или группы;
  • [ ] — Определяет диапазон символов. Например, [0-9] соответствует любой цифре от 0 до 9.

Если базового регулярного выражения (BRE) недостаточно, необходимо включить расширенные регулярные выражения (ERE) или регулярные выражения Perl (PCRE).

Доступные опции утилиты grep для настройки регулярных выражений:

  • опция -E включает расширенные регулярные выражения. Добавляются  ? + | {} () символы;
  • опция -P включает PCRE. Это полноценные регулярные выражения Perl, которые используются в многих языках программирования;
  • опция -F отключает любые регулярные выражения. Шаблон рассматривается как простой текст.

Далее покажу основные примеры использования регулярных выражений, а когда не будет хватать базового регулярного выражения, я буду указывать опцию -P для включения PCRE.

5.1. Найти строки начинающиеся с определенного символа

Например, чтобы найти какие параметры включены (строки не закомментированы) в настройках SSH сервера, необходимо найти строки которые начинаются с букв

grep '^[A-Za-z]' /etc/ssh/sshd_config
Выполнена команда поиска “grep '^[A-Za-z]' /etc/ssh/sshd_config” в консоли Debian, и в результате выведены найденные строки файла sshd_config которые начинаются с латинских заглавных букв

Были найдены все строки которые начинаются с латинской заглавной или прописной буквы.

5.2. Найти строки заканчивающиеся на определенный символ

Например, чтобы найти в каких параметрах php.ini указаны значения в мегабайтах, необходимо найти строки заканчивающиеся на буквы M перед которой стоит цифра

grep '[0-9]M$' /etc/php/php.ini
Выполнена команда поиска “grep '[0-9]M$' /etc/php/php.ini” в консоли Debian, и в результате выведены найденные строки файла php.ini которые заканчиваются на буквы M

Были найдены все строки которые заканчиваются на латинскую заглавную буквы M и перед ней стоит любая цифра.

5.3. Поиск сразу нескольких слов внутри файла

Выполним поиск по словам HOST, SERVER, REQUEST внутри файла PHP конфигурации. Для этого добавим опцию -P для включения полноценного регулярного выражения Perl, а слова запишем через вертикальную черту (| – оператор перечисления значений)

grep -P 'HOST|SERVER|REQUEST' /etc/php/php.ini
Выполнена команда поиска “grep -P 'HOST|SERVER|REQUEST' /etc/php/php.ini” в консоли Debian, и в результате выведены найденные строки файла php.ini которые содержат слова HOST, SERVER, REQUEST

Команду выше можно записать без использования регулярного выражения, а использовать опцию -e, которая позволяет указывать несколько шаблонов поиска.

grep -e 'HOST' -e 'SERVER' -e 'REQUEST' /etc/php/php.ini

5.4. Найти слова которые больше или меньше определенной длины

Найдем все слова, которые 5 и более символов

grep -P '[A-Za-z]{5,}' /etc/php/php.ini
Выполнена команда поиска “grep -P '[A-Za-z]{5,}' /etc/php/php.ini” в консоли Debian, и в результате выведены все строки из файла php.ini которые содержат слова 5 буквы и длиннее

А чтобы найти все слова 5 и менее символов, необходимо доработать регулярное выражение, добавим оператор \b для определения границы слова

grep -P '\b([A-Za-z]{1,5})\b' /etc/php/php.ini
Выполнена команда поиска “grep -P '\b([A-Za-z]{1,5})\b' /etc/php/php.ini” в консоли Debian, и в результате выведены все строки из файла php.ini которые содержат слова не длиннее 5 букв

Выражение [A-Za-z]{1,5} я заключил в парные скобки ( ) для наглядности, в этом примере они не нужны. Эти скобки выполняют примерно аналогичную функцию, что и скобки в обычных математических формулах.