Материал подготовлен командой Simple-Server для администраторов VPS и выделенных серверов. Команды и пути проверяйте на тестовой машине перед production.
Кратко о задаче
Схема команды GREP имеет следующий вид:
grep [ОПЦИИ] [ВЫРАЖЕНИЕ] [ИСТОЧНИКИ]- ОПЦИИ. Специальные параметры (флаги), которые активируют те или иные механики работы утилиты, связанные с поиском выражений и выводом результатов.
- ВЫРАЖЕНИЕ. Регулярное выражение (или обычная строка), содержащее фразу (паттерн, шаблон, последовательность символов), которую необходимо найти.
- ИСТОЧНИКИ. Путь к файлам, внутри которых будет выполнять поиск указанного выражения.
Если же команда GREP используется для преобразования вывода другой команды, то ее схема будет выглядеть немного иначе:
[КОМАНДА] | grep [ОПЦИИ] [ВЫРАЖЕНИЕ]- КОМАНДА. Произвольная команда с собственным набором параметров, вывод которой необходимо отфильтровать.
КОМАНДА. Произвольная команда с собственным набором параметров, вывод которой необходимо отфильтровать.
При этом символ «|» необходим для образования конвейера (pipeline) выполнения команд, который перенаправляет потоки так, что вывод произвольной команды становится вводом команды GREP.
Понять нюансы работы утилиты GREP лучше всего на небольших примерах по поиску вхождений заданных фраз. Поэтому сперва мы создадим несколько текстовых файлов, а после протестируем на них команду GREP.
Для начала подготовим отдельный каталог, в котором будет выполняться поиск:
После чего создадим первый файл:
Содержимым выступит одно из стихотворений Александра Блока:
Ночь, улица, фонарь, аптека,
Бессмысленный и тусклый свет.
Живи еще хоть четверть века —
Всё будет так. Исхода нет.
Умрёшь — начнёшь опять сначала
И повторится все, как встарь:
Ночь, ледяная рябь канала,
Аптека, улица, фонарь.Теперь создадим второй файл:
Его содержимым станет простой скрипт на языке Python:
from datetime import date
dateNow = date.today()
print("Текущее время:", dateNow)Наконец, создадим третий файл:
На этот раз внутри окажется тривиальная HTML-разметка:
<html>
<head>
<title>Некий заголовок</title>
</head>
<body>
<div class="block">
<p>Здесь есть золото</p>
</div>
<div class="block">
<p>Смесь воска и облаков</p>
</div>
<div class="block block_special">
<p>Днесь нет ничего</p>
</div>
</body>
</html>Таким образом с помощью файлов разного формата можно более наглядно разобраться, что делает команда GREP, задействовав всю вариативность функций утилиты.
Регулярные выражения — основа команды GREP. В отличие от обычной строки, регулярные выражения содержат специальные символы, позволяющие задавать фразы с определенной степенью изменчивости.
При использовании утилиты GREP регулярные выражения помещаются в одинарные кавычки:
Таким образом, полная команда может выглядеть так:
grep '^date[[:alpha:]]*' texts/*Консольный вывод в этом случае будет таким:
texts/code.py:dateNow = date.today()Однако использование двойных кавычек позволяет передавать в выражение различные системные данные. Например, можно сперва создать переменную окружения с искомым выражением:
PATTERN="^date[[:alpha:]]*"А потом использовать ее в команде GREP:
grep "$PATTERN" ./texts/*В дополнение к этому, задействование одинарных косых кавычек (клавиша «Ё» в английской раскладке) позволяет использовать команды подпроцессора bash внутри команды GREP.
Например, можно извлечь регулярное выражение из заранее подготовленного файла:
grep `cat somefile` ./texts/*Обратите внимание, что с помощью символа звездочки (маска) можно указать сразу все файлы, находящиеся в каталоге. Тем не менее, команда GREP не запрещает указание только одного файла:
grep '^date[[:alpha:]]*' texts/code.pyПо той причине, что регулярные выражения являются универсальным языком, используемым во многих операционных системах и языках программирования, их изучение — отдельная обширная тема.
Тем не менее, имеет смысл коротко пройтись по основным специальным символам и их функциям.
При этом важно помнить, что регулярные выражения в Linux могут работать в двух режимах — базовом (Basic Regular Expression, BRE) и расширенном (Extended Regular Expression, ERE).
Расширенный режим активируется с помощью дополнительного флага -E. Разница между обоими режимами в количестве доступных спецсимволов и соответственно широте доступного функционала.
Базовый синтаксис позволяет задавать лишь общие формальные конструкции, не учитывающие специфику конфигурации их символов.
Символ циркумфлекса указывает, что искомая последовательность символов должна находиться в начале строки:
Консольный вывод будет следующим:
texts/block:Ночь, улица, фонарь, аптека,
texts/block:Ночь, ледяная рябь канала,Знак доллара указывает, что искомая последовательность символов должна находиться в конце строки:
В консольном терминале появится вот такой вывод:
texts/page.html: <p>Здесь есть золото</p>
texts/page.html: <p>Смесь воска и облаков</p>
texts/page.html: <p>Днесь нет ничего</p>Обратите внимание, что консольный вывод сохраняет оригинальную запись найденных строк так, как они представлены внутри файлов.
Символы обратной косой черты и знака меньше указывают, что искомая фраза должна находиться в начале слова:
Итогом выполнения этой команды станет следующий консольный вывод:
texts/block:Ночь, улица, фонарь, аптека,
texts/block:Аптека, улица, фонарь.Символы обратной косой черты и знака больше указывают, что искомая последовательность символов должна находиться в конце слова:
Консольный вывод после выполнения команды будет таким:
texts/block:Ночь, улица, фонарь, аптека,
texts/block:И повторится все, как встарь:
texts/block:Аптека, улица, фонарь.Начало или конец слова — \b
Указать начало или конец слова можно с помощью другой более универсальной последовательности символов — обратная косой черты и буквы b.
Например, так указывается начало:
Консольный вывод будет таким:
texts/block:Всё будет так. Исхода нет.
texts/page.html: <p>Днесь нет ничего</p>В этом случае вывод в консольном терминале будет следующим:
texts/page.html: <div class="block">
texts/page.html: <div class="block">
texts/page.html: <div class="block block_special">Либо можно указать и то, и другое:
В консольном терминале появится нижеследующий вывод:
texts/block:Бессмысленный и тусклый свет.
texts/page.html: <p>Смесь воска и облаков</p>Некоторые символы в искомых фразах можно оставить без точного указания с помощью символа точки:
Вывод в терминале консоли окажется таким:
texts/page.html: <p>Здесь есть золото</p>
texts/page.html: <p>Смесь воска и облаков</p>
texts/page.html: <p>Днесь нет ничего</p>Расширенный синтаксис, в отличие от базового, позволяет задавать точное количество символов в искомых фразах, тем самым расширяя спектр возможных совпадений.
Чтобы не выполнять команду GREP несколько раз подряд, можно указать сразу несколько шаблонов в одном регулярном выражении:
grep -E '^Ночь|</p>#x27; texts/*Результатом работы этой команды будет комбинированный консольный вывод, содержащий результат поиска двух отдельных регулярных выражений, показанных ранее:
texts/block:Ночь, улица, фонарь, аптека,
texts/block:Ночь, ледяная рябь канала,
texts/page.html: <p>Здесь есть золото</p>
texts/page.html: <p>Смесь воска и облаков</p>
texts/page.html: <p>Днесь нет ничего</p>Интервал повторений — {n, d}
В некоторых случаях определенные символы искомой фразы могут количественно отличаться. Поэтому в регулярном выражении можно указать диапазон допустимого количества определенных символов.
grep -E 'ес{1,2}' texts/*Консольный вывод этого вызова будет таким:
texts/block:Бессмысленный и тусклый свет.
texts/page.html: <p>Здесь есть золото</p>
texts/page.html: <p>Смесь воска и облаков</p>
texts/page.html: <p>Днесь нет ничего</p>Однако часто используемые интервалы повторений удобнее записывать в виде специальных символов, тем самым упрощая внешний вид регулярного выражения.
Одно или более повторений — +
Интервал повторений от одного до бесконечности можно выразить в виде знака сложения:
В этом случае консольный вывод не будет отличаться от предыдущего примера:
texts/block:Бессмысленный и тусклый свет.
texts/page.html: <p>Здесь есть золото</p>
texts/page.html: <p>Смесь воска и облаков</p>
texts/page.html: <p>Днесь нет ничего</p>Ноль или одно повторение — ?
Интервал повторений от 0 до 1 можно выразить в виде знака вопроса:
В результате выполнения этой команды в консольном терминале появится следующий вывод:
texts/page.html: <div class="block">
texts/page.html: <div class="block">
texts/page.html: <div class="block block_special">Вместо одного конкретного символа можно указать целый набор, обрамленный квадратными скобками:
grep -E '[Вв]с[её]' texts/*Консольный вывод в этом случае будет таким:
texts/block:Всё будет так. Исхода нет.
texts/block:И повторится все, как встарь:Диапазон символов — [a-z]
Слишком большой набор допустимых символов можно заменить на диапазон, записанный через тире:
grep -E 'h[a-z]+' texts/*Результатом выполнения этой команды будет следующий вывод:
texts/page.html:<html>
texts/page.html: <head>
texts/page.html: </head>
texts/page.html:</html>Более того, наборы и диапазоны символов можно объединять:
grep -E 'h[abcd-z]+' texts/*Каждый диапазон неявно преобразуется в набор символов:
[a-e]в[abcde][0-6]в[0123456][a-eA-F]в[abcdeABCDEF][A-Fa-e]в[ABCDEFabcde][A-Fa-e0-9]в[ABCDEFabcde0123456789][a-dA-CE-G]в[abcdABCEFG][acegi-l5-9]в[acegijkl56789]
Часто используемые диапазоны можно заменить заранее предопределенным типом символов, название которого указывается в квадратных скобках с двоеточием:
[:lower:] | символы от a до z в нижнем регистре |
|---|---|
[:upper:] | символы от A до Z в верхнем регистре |
[:alpha:] | символы всех букв |
[:digit:] | символы всех цифр |
[:alnum:] | символы всех букв и цифр |
символы от a до z в нижнем регистре
символы от A до Z в верхнем регистре
При этом важно понимать, что тип символов — отдельная синтаксическая конструкция. Это значит, что она сама по себе должна быть обрамлена квадратными скобками, обозначающими набор или диапазон символов:
grep -E '[[:alpha:]]+есь' texts/*Консольный вывод этой команды будет как показано ниже:
texts/page.html: <p>Здесь есть золото</p>
texts/page.html: <p>Смесь воска и облаков</p>
texts/page.html: <p>Днесь нет ничего</p>Чтобы отфильтровать вывод другой команды, после нее необходимо написать символ прямой черты, за которым следует стандартный вызов утилиты GREP, но без указания файлов для поиска:
cat texts/code.py | grep 'import'Консольный вывод, по аналогии с поиском в обычных файлах, будет содержать строки с найденными вхождениями указанных фраз:
from datetime import dateВ данном случае команда cat извлекает содержимое файла и передает его в поток ввода утилиты GREP.
Помимо регулярных выражений можно указать дополнительные ключи команды GREP — специальные опции в формате флагов, уточняющие поиск.
Расширенные регулярные выражения (-E)
Активирует режим расширенных регулярных выражений, разрешающий использовать большее количество специальных символов.
Игнорирование регистра (-i)
Выполняет поиск регулярного выражения, не учитывая регистр символов:
grep -E -i 'вс[её]' texts/*Вот такой консольный вывод соответствует этой команде:
texts/block:Всё будет так. Исхода нет.
texts/block:И повторится все, как встарь:При этом флаги можно указывать слитно:
grep -Ei 'вс[её]' texts/*Выполняет поиск таким образом, чтобы указанное регулярное выражение являлось полноценным словом (а не его подстрокой) в найденной строке:
Обратите внимание, что при указании обычной строки, не содержащий специальные символы, кавычки можно не указывать.
Результатом выполнения этой команды станет вот такой консольный вывод:
texts/block:Бессмысленный и тусклый свет.
texts/page.html: <p>Смесь воска и облаков</p>Инвертированный поиск (-v)
По умолчанию команда GREP выводит в консольный терминал строки с найденными фразами. Однако результат можно инвертировать, выводя в консольный терминал строки без найденных фраз:
grep -v 'today' script.pyКонсольный вывод будет содержать все строки кроме той, в которой было найдено вхождение:
from datetime import date
print("Текущее время:", dateNow)Чтобы не вызывать команду несколько раз, можно сразу указать несколько выражений:
grep -e 'Ночь' -e 'html' texts/*Результат работы этой команды будет идентичен такой записи:
grep -E 'Ночь|html' texts/*В обоих случаях в консольном терминале появится следующий вывод:
texts/block:Ночь, улица, фонарь, аптека,
texts/block:Ночь, ледяная рябь канала,
texts/page.html:<html>
texts/page.html:</html>Выполняет рекурсивный поиск в указанной директории до максимальной глубины вложенности:
grep -r '[Ff]ilesystem' /rootВ консольном терминале появится вывод, содержащий пути файлов, находящихся на разных уровнях вложенности относительно указанной директории:
Поиск специальных символов (-F)
Разрешает использование специальных символов в качестве символов искомой фразы:
Без указания этого флага в консольном терминале возникнет ошибка:
grep: Invalid regular expressionАльтернативой этому флагу будет использование символа экранирования в виде обратной косой черты (\):
Включение файлов (--include)
Позволяет ограничить поиск только указанными файлами:
grep --include='*.py' 'date' texts/*Консольный вывод будет таким:
texts/code.py:from datetime import date
texts/code.py:dateNow = date.today()
texts/code.py:print("Текущее время:", dateNow)Эту команду можно также записать без маски, используя дополнительный флаг рекурсивного поиска.:
grep -r --include='*.py' 'date' textsИсключение файлов (--exclude)
Избирательно исключает определенные файлы из списка источников поиска:
grep --exclude='*.py' 'и' texts/*Консольный вывод окажется следующим:
texts/block:Ночь, улица, фонарь, аптека,
texts/block:Бессмысленный и тусклый свет.
texts/block:Живи еще хоть четверть века —
texts/block:И повторится все, как встарь:
texts/block:Аптека, улица, фонарь.
texts/page.html: <title>Некий заголовок</title>
texts/page.html: <p>Смесь воска и облаков</p>
texts/page.html: <p>Днесь нет ничего</p>Некоторые параметры команды GREP влияют только на вывод результатов поиска, улучшая его информативность и наглядность.
Для повышения информативности результата работы утилиты GREP можно добавить номера строк, в которых были найдены искомые фразы:
Каждая строка в выводе будет дополнена номером строки
texts/page.html:8: <p>Здесь есть золото</p>
texts/page.html:12: <p>Смесь воска и облаков</p>
texts/page.html:16: <p>Днесь нет ничего</p>Выводит заданное количество строк, идущих перед строками с найденными вхождениями:
После флага указывается число предыдущих строк, которые требуется вывести в консольный терминал:
texts/page.html- </div>
texts/page.html-
texts/page.html- <div class="block">
texts/page.html: <p>Смесь воска и облаков</p>Выводит заданное количество строк, идущих после строк с найденными вхождениями:
После флака указывается число последующих строк, которые требуется вывести в консольный терминал:
texts/page.html: <p>Смесь воска и облаков</p>
texts/page.html- </div>
texts/page.html-
texts/page.html- <div class="block block_special">Выводит заданное количество строк, идущих как перед, так и после строк с найденными вхождениями:
После флака указывается число предыдущих и последующих строк, которые требуется вывести в консольный терминал:
texts/page.html- </div>
texts/page.html-
texts/page.html- <div class="block">
texts/page.html: <p>Смесь воска и облаков</p>
texts/page.html- </div>
texts/page.html-
texts/page.html- <div class="block block_special">Вместо списка найденных строк команды GREP выводит только их количество:
Консольный вывод будет содержать количество найденных совпадений во всех указанных файлах:
texts/block:5
texts/code.py:0
texts/page.html:3Если же в качестве источника указывается лишь один файл:
То консольный вывод будет содержать только число:
Флаг позволяет вывести только названия файлов, в которых найдены совпадения:
В этом случае консольный вывод будет таким:
texts/block
texts/page.htmlСокращает количество выводящихся в консольный терминал строк до указанного рядом с флагом:
Консольный вывод будет таким:
texts/block:Ночь, улица, фонарь, аптека,
texts/block:Бессмысленный и тусклый свет.
texts/page.html: <title>Некий заголовок</title>
texts/page.html: <p>Смесь воска и облаков</p>Как видно, ограничивающее число влияет не на весь вывод в целом, а на строки каждого файла.
Ищет точное совпадение целой строки без какой-либо вариативности:
grep -x 'Всё будет так. Исхода нет.' texts/*Консольный вывод следующий:
texts/block:Всё будет так. Исхода нет.Нужен сервер для практики? Арендуйте VPS/VDS в России — root-доступ, NVMe, DDoS-защита и поддержка 24/7.