Использование grep в чистом виде

$ grep '12:00' /home/david/backup/log.txt

Эта команда показывает как можно использовать grep для того чтобы получить строки из файла содержащие подстроку указаную в командной строке. Файл не обязательно должен оканчиваться на .txt. Показаная выше команда производит поиск подстроки 12.00 в файле /home/david/backup/log.txt и отображает все строки где эта подстрока встречается.

Эта комбинация может быть использована например для поиска бекапов которые происходили в 12:00.

$ grep -v '12.00' /home/david/backup/log.txt

А вот эта команда (с использованием ключа -v) наоборот покажет только те строки где подстрока ’12:00? не встречается.

$ grep -l 'delay' /code/*.c

Эта команда будет искать все файлы оканчивающиеся на .c и текст в найденых файлах соответствующий подстроке 'delay' и в конечном итоге выведет только имена файлов где эта подстрока встречается.

$ grep -w '\<bay' * $ grep -w 'watch\>' *

Эта команда уже более сложная и состоит из комбинации двух команд grep. Первая ищет строки которые начинаются со слова ‘bay’ а вторая строки которые заканчиваются на слово ‘watch’.

Использование grep вместе с потоками

$ ls -l | grep rwxrwxrwx

Вы наверно уже знаете что команда ls -l отображает подробный список файлов в директории. Часть grep rwxrwxrwx фильтрует результат полученый от ls -l и выводит только те директории у которых установлены соответствующие права доступа. В данном случае это открытый доступ на чтение, запись и поиск для всех пользователей и групп. Так что вместо того чтобы увидеть полный список файлов вы увидите только те файлы у которых установлены нужные вам права доступа.

Вывод от команды grep может также быть направлен потоком в другую команду, например как в следующем примере:

$ du | grep 'mp3' | more

Вы должны уже догадаться что делает указаная выше команда 

 Если не догадались то все просто — она выводит постранично список mp3 файлов найденых в текущей директории. Все просто 

$ grep '^#' /home/david/script1 | more

Эта команда отобразит все строки в файле /home/david/script1 которые начинаются с символа ‘#’. Определение тип ‘^#’ означает что символ ‘#’ должен быть первым символом с троке.

$ grep -v '^[0-9]' /home/david/backup/log.txt | more

Эта команда ищет строки содержащие в первом символе цифры от 0 до 9 а потом выводит только те строки которые не попали в результаты поиска. Как вы видите — был использован ключ ‘-v’ означающий реверсивный поиск.

Важно: Необходимо заключать искомые строки в одинарные кавычки как указано в двух предыдущих примерах для того чтобы интерпретатор командной строки мог воспринимать их корректно. Иначе интерпретатор может понять это как другую команду и результат выполнения будет непредсказуем.

Некоторые дополнительные ключи команды grep:

  • -v : Выводи реверсивные результаты. Вместо того чтобы вывести строки где искомое было найдено — выводи те строки где искомой подстроки нет.
  • -c : Отключает стандартный способ вывода результата и вместо этого отображает только число обозначающее количество найденых строк.
  • -i : Делает поиск регистронезависимым
  • -w : Ведет поиск по цельным словам. Например при обычном поиске строки ‘wood’ grep может найти слово ‘hollywood’. А если используется данный ключ то будут найдены только строки где есть слово ‘wood’.
  • -l : Выводит только имена файлов где была найдена строка.
  • -r : Производит поиск рекурсивно по всем поддиректориям.

Это важно в связи с 

# man grep | grep -iB 2 freebsd
       -P, --perl-regexp
              Interpret PATTERN as a Perl regular expression.  This option  is
              not supported in FreeBSD.

Для начала о том как мы обычно grep’аем файлы.

Используя cat:

[email protected]:/ # cat /var/run/dmesg.boot | grep CPU:
CPU: Intel(R) Core(TM)2 Quad CPU    Q9550  @ 2.83GHz (2833.07-MHz K8-class CPU)

Но зачем? Ведь можно и так:

[email protected]:/ # grep CPU: /var/run/dmesg.boot
CPU: Intel(R) Core(TM)2 Quad CPU    Q9550  @ 2.83GHz (2833.07-MHz K8-class CPU)

Или вот так (ненавижу такую конструкцию):

[email protected]:/ # </var/run/dmesg.boot grep CPU:
CPU: Intel(R) Core(TM)2 Quad CPU    Q9550  @ 2.83GHz (2833.07-MHz K8-class CPU)

Зачем-то считаем отобранные строки с помощью wc:

[email protected]:/ # grep WARNING /var/run/dmesg.boot | wc -l
       3

Хотя можно:

[email protected]:/ # grep WARNING /var/run/dmesg.boot -c
3

Сделаем тестовый файлик:

test.txt

И приступим к поискам:

Опция -w позволяет искать по слову целиком:

[email protected]:/ # grep -w 'seven' test.txt
seven eight one eight three
 sixteen seventeen eighteen seven
        twenty seven

А если нужно по началу или концу слова?

[email protected]:/ # grep '\<seven' test.txt
seven eight one eight three
 sixteen seventeen eighteen seven
sixteen seventeen eighteen
        twenty seven
[email protected]:/ # grep 'seven\>' test.txt
seven eight one eight three
 sixteen seventeen eighteen seven
        twenty seven
twentyseven

Стоящие в начале или конце строки?

[email protected]:/ # grep '^seven' test.txt
seven eight one eight three
[email protected]:/ # grep 'seven$' test.txt
 sixteen seventeen eighteen seven
        twenty seven
twentyseven
[email protected]:/ #

Хотите увидеть строки в окрестности искомой?

[email protected]:/ # grep -C 1 twentyseven test.txt
#comment UP
twentyseven
        #comment down

Только снизу или сверху?

[email protected]:/ # grep -A 1 twentyseven test.txt
twentyseven
        #comment down
[email protected]:/ # grep -B 1 twentyseven test.txt
#comment UP
twentyseven

А ещё мы умеем так

[email protected]:/ # grep "twenty[1-4]" test.txt
twenty1
twenty3

И наоборот исключая эти

[email protected]:/ # grep "twenty[^1-4]" test.txt
        twenty seven
twentyseven
twenty5
twenty7

Разумеется grep поддерживает и прочие базовые квантификаторы, метасимволы и другие прелести регулярок

Пару практических примеров:

[email protected]:/ # cat /etc/resolv.conf
#options edns0
#nameserver 127.0.0.1
nameserver 8.8.8.8
nameserver 77.88.8.8
nameserver 8.8.4.4

Отбираем только строки с ip:

[email protected]:/ # grep -E "[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}" /etc/resolv.conf
#nameserver 127.0.0.1
nameserver 8.8.8.8
nameserver 77.88.8.8
nameserver 8.8.4.4

Работает, но так симпатичнее:

[email protected]:/ # grep -E '\b[0-9]{1,3}(\.[0-9]{1,3}){3}\b' /etc/resolv.conf
#nameserver 127.0.0.1
nameserver 8.8.8.8
nameserver 77.88.8.8
nameserver 8.8.4.4

Уберём строку с комментарием?

[email protected]:/ # grep -E '\b[0-9]{1,3}(\.[0-9]{1,3}){3}\b' /etc/resolv.conf | grep -v '#'
nameserver 8.8.8.8
nameserver 77.88.8.8
nameserver 8.8.4.4

А теперь выберем только сами ip

[email protected]:/ # grep -oE '\b[0-9]{1,3}(\.[0-9]{1,3}){3}\b' /etc/resolv.conf | grep -v '#'
127.0.0.1
8.8.8.8
77.88.8.8
8.8.4.4

Вот незадача… Закомментированная строка вернулась. Это связано с особенностью обработки шаблонов. Как быть? Вот так:

[email protected]:/ # grep -v '#' /etc/resolv.conf | grep -oE '\b[0-9]{1,3}(\.[0-9]{1,3}){3}\b'
8.8.8.8
77.88.8.8
8.8.4.4

Здесь остановимся на инвертировании поиска ключом -v

Допустим нам нужно выполнить «ps -afx | grep ttyv»

[email protected]:/ # ps -afx | grep ttyv
 1269 v1  Is+       0:00.00 /usr/libexec/getty Pc ttyv1
 1270 v2  Is+       0:00.00 /usr/libexec/getty Pc ttyv2
 1271 v3  Is+       0:00.00 /usr/libexec/getty Pc ttyv3
 1272 v4  Is+       0:00.00 /usr/libexec/getty Pc ttyv4
 1273 v5  Is+       0:00.00 /usr/libexec/getty Pc ttyv5
 1274 v6  Is+       0:00.00 /usr/libexec/getty Pc ttyv6
 1275 v7  Is+       0:00.00 /usr/libexec/getty Pc ttyv7
48798  2  S+        0:00.00 grep ttyv

Всё бы ничего, но строка «48798 2 S+ 0:00.00 grep ttyv»нам не нужна. Используем -v

[email protected]:/ # ps -afx | grep ttyv | grep -v grep
 1269 v1  Is+       0:00.00 /usr/libexec/getty Pc ttyv1
 1270 v2  Is+       0:00.00 /usr/libexec/getty Pc ttyv2
 1271 v3  Is+       0:00.00 /usr/libexec/getty Pc ttyv3
 1272 v4  Is+       0:00.00 /usr/libexec/getty Pc ttyv4
 1273 v5  Is+       0:00.00 /usr/libexec/getty Pc ttyv5
 1274 v6  Is+       0:00.00 /usr/libexec/getty Pc ttyv6
 1275 v7  Is+       0:00.00 /usr/libexec/getty Pc ttyv7

Некрасивая конструкция? Потрюкачим немного:

[email protected]:/ # ps -afx | grep "[t]tyv"
 1269 v1  Is+       0:00.00 /usr/libexec/getty Pc ttyv1
 1270 v2  Is+       0:00.00 /usr/libexec/getty Pc ttyv2
 1271 v3  Is+       0:00.00 /usr/libexec/getty Pc ttyv3
 1272 v4  Is+       0:00.00 /usr/libexec/getty Pc ttyv4
 1273 v5  Is+       0:00.00 /usr/libexec/getty Pc ttyv5
 1274 v6  Is+       0:00.00 /usr/libexec/getty Pc ttyv6
 1275 v7  Is+       0:00.00 /usr/libexec/getty Pc ttyv7

Также не забываем про | (ИЛИ)

[email protected]:/ # vmstat -z | grep -E "(sock|ITEM)"
ITEM                   SIZE  LIMIT     USED     FREE      REQ FAIL SLEEP
socket:                 696, 130295,      30,      65,   43764,   0,   0

ну и тоже самое, иначе:

[email protected]:/ # vmstat -z | grep "sock\|ITEM"
ITEM                   SIZE  LIMIT     USED     FREE      REQ FAIL SLEEP
socket:                 696, 130295,      30,      65,   43825,   0,   0

Ну и если об использовании регулярок в grep’e помнят многие, то об использовании POSIX классов как-то забывают, а это тоже иногда удобно.

POSIX

Отберём строки с заглавными символами:

[email protected]:/ # grep "[[:upper:]]" test.txt
#comment UP

Ну и ещё пару трюков для затравки. 

Первый скорее академичный. За лет 15 ни разу его не использовал:

Нужно из нашего тестового файла выбрать строки содержащие six или seven или eight:

Пока всё просто:

[email protected]:/ # grep -E "(six|seven|eight)" test.txt
seven eight one eight three
 sixteen seventeen eighteen seven
sixteen seventeen eighteen
        twenty seven
twentyseven

А теперь только те строки в которых six или seven или eight встречаются несколько раз. Эта фишка именуется Backreferences

[email protected]:/ # grep -E "(six|seven|eight).*\1" test.txt
seven eight one eight three
 sixteen seventeen eighteen seven

Ну и второй трюк, куда более полезный. Необходимо вывести строки в которых 504 с обеих сторон ограничено табуляцией.

Ох как тут не хватает поддержки PCRE…

Использование POSIX-классов не спасает:

[email protected]:/ # grep "[[:blank:]]504[[:blank:]]" test.txt
one 504 one
one     504     one
one     504 one

На помощь приходит конструкция [CTRL+V][TAB]:

[email protected]:/ # grep "     504     " test.txt
one     504     one

Что ещё не сказал? Разумеется, grep умеет искать в файлах/каталогах и, разумеется, рекурсивно. Найдём в исходниках код, где разрешается использование Intel’ом сторонних SFP-шек. Как пишется allow_unsupported_sfp или unsupported_allow_sfp не помню. Ну да и ладно — это проблемы grep’а:

[email protected]:/ # grep -rni allow /usr/src/sys/dev/ | grep unsupp
/usr/src/sys/dev/ixgbe/README:75:of unsupported modules by setting the static variable 'allow_unsupported_sfp'
/usr/src/sys/dev/ixgbe/ixgbe.c:322:static int allow_unsupported_sfp = TRUE;
/usr/src/sys/dev/ixgbe/ixgbe.c:323:TUNABLE_INT("hw.ixgbe.unsupported_sfp", &allow_unsupported_sfp);
/usr/src/sys/dev/ixgbe/ixgbe.c:542:     hw->allow_unsupported_sfp = allow_unsupported_sfp;
/usr/src/sys/dev/ixgbe/ixgbe_type.h:3249:       bool allow_unsupported_sfp;
/usr/src/sys/dev/ixgbe/ixgbe_phy.c:1228:                                if (hw->allow_unsupported_sfp == TRUE) {
Оставьте ответ