В основном я использую регулярное выражение. В выводе я хотел бы видеть только те строки, которые соответствуют моему reg exp.
В группе файлов XML (в основном это однострочные файлы с огромным количеством данных в строке), я хотел бы получить все слова, начинающиеся с MAIL_ .
Я хотел бы, чтобы команда grep на оболочке выдавала только совпадающие слова, а не всю строку (в данном случае это весь файл).
Как мне это сделать?
Я пытался
grep -Gril MAIL_* .
grep -Grio MAIL_* .
grep -Gro MAIL_* .
Прежде всего, для GNU grep, установленного с Ubuntu, флаг -G (использовать базовое регулярное выражение) является значением по умолчанию, поэтому вы можете опустить его, но, что еще лучше, используйте расширенное регулярное выражение с -Е.
Флаг -r означает рекурсивный поиск в файлах каталога, это то, что вам нужно.
И вы правы, используя флаг -o для вывода совпадающей части строки. Кроме того, чтобы не указывать имена файлов, вам понадобится флаг -h.
Единственная ошибка, которую вы допустили, - это само регулярное выражение. Вы пропустили спецификацию символов перед *. Ваша команда должна выглядеть так:
grep -Ehro 'MAIL_[^[:space:]]*' .
Пример вывода (не рекурсивный):
$ echo "Some garbage MAIL_OPTION comes MAIL_VALUE here" | grep -Eho 'MAIL_[^[:space:]]*'
MAIL_OPTION
MAIL_VALUE
grep -o or --only-matching
выводит только соответствующий текст вместо полных строк, но проблема может заключаться в вашем регулярном выражении, которое не является достаточно ограничительным или жадным и фактически соответствует всему файлу.
Попробуйте следующую команду
grep -Eo 'MAIL_[[:alnum:]_]*'
Из вашего комментария к ответу Тора следует, что вы также хотите различать, является ли текст MAIL_.*
текстовым узлом или атрибутом, а не просто изолировать его всякий раз, когда он появляется в XML-документе. Grep не может анализировать XML, для этого нужен соответствующий парсер XML.
Парсер командной строки xml - это xmlstarlet. Он поставляется в Ubuntu.
Используя его на этом примере файла:
$ cat test.xml
<some_root>
<test a="MAIL_as_attribute">will be printed if you want matching attributes</test>
<bar>MAIL_as_text will be printed if you want matching text nodes</bar>
<MAIL_will_not_be_printed>abc</MAIL_will_not_be_printed>
</some_root>
Для выбора текстовых узлов можно использовать:
$ xmlstarlet sel -t -m '//*' -v 'text()' -n test.xml | grep -Eo 'MAIL_[^[:space:]]*'
MAIL_as_text
А для выбора атрибутов:
$ xmlstarlet sel -t -m '//*[@*]' -v '@*' -n test.xml | grep -Eo 'MAIL_[^[:space:]]*'
MAIL_as_attribute
Краткие пояснения:
//*
- это выражение XPath, которое выбирает все элементы в документе и text()
выводит значение их дочерних текстовых узлов, поэтому все, кроме текстовых узлов, отфильтровывается//*[@*]
- это выражение XPath, которое выбирает все атрибуты в документе и затем @*
выводит их значение