Алексей Дмитриев, 3 января 2009
HuMan: grepВведениеКоманда grep, одна из самых известных и употребительных команд Юнксовидных ОС, ведет свое начало от первого текстового редактора Юникс - ed. В этом редакторе была команда g/re/p (global/regular expression/print), которая и дала свое название новой программе.Команда grep служит для поиска строк, содержащих заданный пользователем образец. grep ОБРАЗЕЦ имя_файла Причем обязательным для ввода является только ОБРАЗЕЦ, можно обойтись даже без имени файла (аргумента). Команда grep без опций и аргумента.Если не указано имени файла, то команда обрабатывает стандартный ввод, например строки, набранные на клавиатуре:
$ grep кот у меня есть кошка,(Enter) вернее это кот,(Enter) вернее это кот, который умеет(Enter) который умеет ловить мышей.(Enter) (Ctrl+c) В скобках показано, когда я нажимал клавишу Enter, чтобы перейти на новую строку. Одновременно, при нажатии Enter, программа выводила строки, содержащие ОБРАЗЕЦ (кот), отсюда и удвоение этих строк. Видно, что команда реагировала просто на сочетание букв, а не на слово "кот", иначе строка со словом "который" не попала бы в вывод. Тут мы подошли к очень важному определению строки. Строкой команда grep (как и все остальные команды Юникс) считает все символы, находящиеся между двумя символами новой строки. Эти невидимые на экране символы возникают в тексте каждый раз, когда пользователь нажимает клавишу Enter. В Юниксовидных системах символ новой строки обозначается обратным слэшем с буквой n (\n). Таким образом, строка может быть любого размера, начиная с одного символа и до многомегабайтного текста. И команда grep честно выведет эту строку, при условии, что она содержит ОБРАЗЕЦ. Работа с файламиКоманда grep может обрабатывать любое количество файлов одновременно. Создадим три файла:
123.txt: alice.txt: ast.txt: 1234 Алиса очень Символ астериска 5678 красивая девочка, обозначается (*) 89*0 у нее такая ****** звездочкой. длинная коса! И дадим команду:
$ grep '*' 123.txt ast.txt alice.txt 123.txt:89*0 ast.txt:обозначается (*). alice.txt:у нее такая ****** В выводе перечислены файлы, и указано, в каком из них какая строка содержит символ астериска. ОБРАЗЕЦ (*) пришлось взять в кавычки, чтобы командный интерпретатор понял, что имеется в виду символ, а не условный знак. Попробуйте без кавычек, увидите - ничего не получится. Команда grep вовсе не ограничена одним выражением в качестве ОБРАЗЦА, можно задавать хоть целые фразы. Только их нужно заключать в кавычки (одинарные или двойные):
$ grep 'ная ко' 123.txt ast.txt alice.txt alice.txt:длинная коса! Возможности поиска при помощи команды grep могут быть значительно расширены применением групповых символов. Например, уже упоминавшийся астериск (звездочка) используется для представления любого символа или группы символов, если речь идет о тексте, и любого файла или группы файлов, если речь идет о директории. Создадим директорию /example, в которую поместим файлы наших примеров: 123.txt, ast.txt, alice.txt и дадим команду:
$ grep '*' example/* example/123.txt:89*0 example/alice.txt:у нее такая ****** example/ast.txt:обозначается (*) То есть мы приказали просмотреть все файлы директории /example. Таким способом можно обследовать такие огромные директории как /usr, /dev, и любые другие. Опция -rЕще больше увеличит зону поисков опция -r, которая заставит команду grep рекурсивно обследовать все дерево указанной директории, то есть субдиректории, субдиректории субдиректорий, и так далее вплоть до файлов. Например:
$ grep -r menu /boot Опция -iПриказывает команде игнорировать регистр символов, таким образом, поиск будет производиться как среди заглавных, так и среди строчных букв.Опция -cЭта опция не выводит строки, а подсчитывает количество строк, в которых обнаружен ОБРАЗЕЦ. Например:
$ grep -c root /etc/group 8 То есть в восьми строках файла /etc/group встречается сочетание символов root. Опция -nПри использовании этой опции вывод команды grep будет указывать номера строк, содержащих ОБРАЗЕЦ:
$ grep -n print /etc/printcap 1:# /etc/printcap 3:# See "man printcap" for information on editing this file. 5:# In most cases it is better to use a tool to write the printcap 9:# cupsd print daemon at this URL: http://localhost:631 Опция -vВыполняет работу, обратную обычной - выводит строки, в которых ОБРАЗЕЦ не встречается:
$ grep -v print /etc/printcap # # # for you (at least initially), such as apsfilter # (/usr/share/apsfilter/SETUP, used in conjunction with the # LPRng lpd daemon), or with the web interface provided by the # (if you use CUPS).
Опция -w--word-regexpЗаставит команду grep искать только строки, содержащие все слово или фразу, составляющую ОБРАЗЕЦ. Например:
$ grep -w "длинная ко" example/* Не дает вывода, то есть не находит строк содержащих выражение "длинная ко". А вот команда:
$ grep -w "длинная коса" example/* example/alice.txt:длинная коса! находит точное соответствие в файле alice.txt. Опция -xЕще более строгая. Она отберет только те строки исследуемого файла или файлов, которые полностью совпадают с ОБРАЗЦОМ.
$ grep -x "1234" example/* example/123.txt:1234 Внимание: Мне попадались (на собственном компьютере) версии grep (например, GNU 2.5), в которых опция -x работала неадекватно. В то же время, другие версии (GNU 2.5.1) работали прекрасно. Если что-то не ладится с этой опцией, попробуйте другую версию, или обновите свою. Опция -lКоманда grep с этой опцией не возвращает строки, содержащие ОБРАЗЕЦ, но сообщает лишь имена файлов, в которых данный образец найден:
$ grep -l 'Алиса' example/* example/alice.txt Замечу, что сканирование каждого из заданных файлов продолжается только до первого совпадения с ОБРАЗЦОМ. Опция -LНаоборот, сообщает имена тех файлов, где не встретился ОБРАЗЕЦ:
$ grep -L 'Алиса' example/* example/123.txt example/ast.txt Как мы имели случай заметить, команда grep, в поисках соответствия ОБРАЗЦУ, просматривает только содержимое файлов, но не их имена. А так часто нужно найти файл по его имени или другим параметрам, например времени модификации! Тут нам придет на помощь простейший программный канал (pipe). При помощи знака программного канала - вертикальной черты (|) мы можем направить вывод команды ls, то есть список файлов в текущей директории, на ввод команды grep, не забыв указать, что мы, собственно, ищем (ОБРАЗЕЦ). Например:
Desktop$ ls | grep grep grep/ grep-ru.txt Находясь в директории Desktop, мы "попросили" найти на Рабочем столе все файлы, в названии которых есть выражение "grep". И нашли одну директорию grep/ и текстовой файл grep-ru.txt, который я в данный момент и пишу. Если мы хотим искать по другим параметрам файла, а не по его имени, то следует применить команду ls -l, которая выводит файлы со всеми параметрами:
Desktop$ ls -l | grep 2008-12-30 -rw-r--r-- 1 ya users 27 2008-12-30 08:06 123.txt drwxr-xr-x 2 ya users 4096 2008-12-30 08:49 example/ -rw-r--r-- 1 ya users 11931 2008-12-30 14:59 grep-ru.txt И вот мы получили список всех файлов, модифицированных 30 декабря 2008 года. Команда grep незаменима при просмотре логов и конфигурационных файлов. Классически примером использования команды grep стал программный канал с командой dmesg. Команда dmesg выводит те самые сообщения ядра, которые мы не успеваем прочесть во время загрузки компьютера. Допустим, мы подключили через USB порт новый принтер, и теперь хотим узнать, как ядро "окрестило" его. Дадим такую команду:
$ dmesg | grep -i usb Опция -i необходима, так как usb часто пишется заглавными буквами. Проделайте этот пример самостоятельно - у него длинный вывод, который не укладывается в рамки данной статьи. Немного хитростейЕсли продолжить описание множества опций команды grep, то статья станет утомительной и нечитаемой. Поэтому, рассмотрев необходимый минимум опций, можно развлечься всякими хитростями при применении этой замечательной команды.Хитрость перваяКак заставить grep указать в выводе имя файла, где найдено соответствие ОБРАЗЦУ? Например, мы хотим найти строку, содержащую выражение "красивая девочка" в файле alice.txt, да так, чтобы в выводе фигурировало имя файла (для отчета). Если просто дать команду:
$ grep -w 'красивая девочка' alice.txt красивая девочка, То никакого имени файла там не будет. Но стоит добавить в аргументы еще один файл, как все заработает. Обычно, чтобы избежать неожиданностей, указывают файл /dev/null:
$ grep -w 'красивая девочка' alice.txt /dev/null alice.txt:красивая девочка, Хитрость втораяИспользуя "чистые" опции команды grep, мы можем получить все строки, содержащие ОБРАЗЕЦ либо в составе других слов (без опций), либо в виде заданного слова (опция -w). А как найти слова, которые заканчиваются на -ОБРАЗЕЦ или начинаются с ОБРАЗЕЦ-? Для этого существуют специальные значки: \< означает, что ОБРАЗЕЦ будет началом слова, и \>, означающий, что ОБРАЗЕЦ будет концом слова.
$ grep 'kot' kot.txt kot kotoroe antrekot kotovasiya okot skotobaza nekotoroe Это файл kot.txt целиком.
$ grep 'kot\>' kot.txt kot antrekot okot А это слова, оканчивающиеся на -kot.
$ grep '\<kot' kot.txt kot kotoroe kotovasiya Эти начинаются на kot-. $ grep '\<kot\>' kot.txt kot А вот "чистый" кот. Прошу простить за транслитерацию, но с нашими буквами эта хитрость как-то не срабатывает, а с английскими словами не все поймут. Хитрость третья.Как быть, если ОБРАЗЕЦ начинается с дефиса, ведь команда примет его за опцию?Попробуем:
$ grep '--анонимность' anonim.txt grep: unrecognized option `--анонимность' Так и есть - принимает за опцию. Ну так дадим ей опцию -e, которая означает: "Воспринимать ОБРАЗЕЦ только как образец".
$ grep -e '--анонимность' anonim.txt --анонимность Совсем другое дело. Хитрость четвертая.Как посмотреть соседние строчки?
$ grep -C 2 -e '--анонимность' anonim.txt Требуется соблюсти следующие условия: --анонимность --секретность --неразглашение. Просмотр вверх и вниз на две строки.
$ grep -A 1 -e '--анонимность' anonim.txt --анонимность --секретность Просмотр вниз на одну строку.
$ grep -B 1 -e '--анонимность' anonim.txt Требуется соблюсти следующие условия: --анонимность Просмотр вверх на одну строку. Хитрость пятая.$ grep -r menu /boot Бинарный файл /boot/grub/stage2 совпадает Бинарный файл /boot/grub/stage2_eltorito совпадает /boot/grub/grub.txt:Highlight the menu entry you want to edit and press 'e', then /boot/grub/grub.txt:Press the [Esc] key to return to the GRUB menu. /boot/grub/menu.lst:# GRUB configuration file '/boot/grub/menu.lst'. /boot/grub/menu.lst:gfxmenu (hd0,3)/boot/message Что означают сообщения в первых двух строках вывода? Сообщение "Бинарный файл совпадает" ("Binary file matches") появляется, когда совпадение с образцом встречается в бинарных файлах. Если бы grep вывел строки из таких файлов на дисплей, толку было бы немного, а на дисплее могла возникнуть неразбериха (а может быть, и чего похуже, если драйвер терминала воспримет какие-либо фрагменты бинарного файла как команды). Если вы хотите все-таки увидеть эти строки, то применяйте опцию -a или --binary-files=text. Если хотите подавить вывод сообщений "Бинарный файл совпадает", то применяйте опцию -I или --binary-files=without-match. Хитрость шестая.Как искать строки, содержащие несколько ОБРАЗЦОВ?Применить программный канал, канализируя вывод одной команды grep с вводом следующей команды grep.
$ grep 'у' example/* | grep '*' example/alice.txt:у нее такая ****** Первый grep ищет у нас "у", а второй - "*" и оба находят искомое в одной строке: "у нее такая ******". Можно сделать эту цепочку команд grep любой длины, было бы чего искать, да строчки достаточно длинные :-) Хитрость седьмая, и пока последняя.Можно ли искать одновременно в стандартном вводе и в файле?. Можно, если перед именем файла поставить дефис:
$ echo многие употребляют астериск неправильно | grep 'астериск' - example/* (стандартный ввод):многие употребляют астериск неправильно example/ast.txt:Символ астериска Внимание: Если перед дефисом и после него не будет пробелов, то команда не сработает. Но настало время вернуться к опциям команды grep. Пока я занимался хитростями, успел позабыть, какие из опций уже описал, а какие нет. Поэтому я дал команду:
$ grep 'Опция' grep-ru.txt > option.txt и получил файл option.txt, в котором перечислены все фигурирующие в нем опции. Общее количество опций программы подавляет, поэтому пойдем по алфавиту, пропуская те, что я уже описал. Опция -f имя_файла--file=имя_файлаВесьма полезная опция, когда нужно искать несколько ОБРАЗЦОВ, причем не в одной строке, как мы делали в шестой Хитрости, а в разных. Для того чтобы воспользоваться этой опцией, нужно составить файл, в котором поместить искомые ОБРАЗЦЫ по одному на строчке:
pattern.txt: nobody root ya А затем дать команду:
# grep -f pattern.txt /etc/passwd nobody:x:65534:65533:nobody:/var/lib/nobody:/bin/bash root:x:0:0:root:/root:/bin/bash ya:x:1000:100:alex dmitriev:/home/ya:/bin/bash Предупреждение: Эта полезная опция, к сожалению, работает не на всех версиях grep. На версии GNU grep 2.5 работает неадекватно, а на GNU grep 2.5.1 - прекрасно. Так что обновляйтесь, господа. Текущая стабильная версия GNU grep - 2.5.3. Опция -o--only-matchingВозвращает не всю строку, где найдено соответствие ОБРАЗЦУ, а только совпадающую с ОБРАЗЦОМ часть строки. Без опции -o:
$ grep 'английскими' grep-ru.txt Прошу простить за транслитерацию, но с нашими буквами как-то эта хитрость не срабатывает, а с английскими словами не все поймут. А вот с опцией -o:
$ grep -o 'английскими' grep-ru.txt английскими Опция -q--quiet --silentНичего не выдает на стандартных вывод. В случае нахождения соответствия с ОБРАЗЦОМ немедленно отключается с нулевым статусом. Отключается также при обнаружении ошибки. Для чего это - не знаю. У меня получалось, что программа мгновенно прекращает работу, есть ли совпадения, нет ли, без всяких сообщений, в том числе и о нулевом статусе. Опробовал обе доступные версии grep. Опция -s--no-messagesПодавляет сообщения о несуществующих или нечитаемых файлах. Предупреждение: традиционные версии последних двух опции (-q и -s) не соответствуют стандарту POSIX.2 и не совпадают с GNU версиями. Поэтому их нельзя применять в скриптах для командной оболочки. Просто перенаправляйте вывод на /dev/null. Опции - расширения GNUОпции
|