Может ли grep выводить только указанные группы, которые соответствуют?

Скажем, у меня есть файл:

# file: 'test.txt' foobar bash 1 bash foobar happy foobar 

Я только хочу знать, какие слова появляются после «foobar», поэтому я могу использовать это регулярное выражение:

 "foobar \(\w\+\)" 

Скобки указывают, что у меня есть особый интерес к слову сразу после foobar. Но когда я делаю grep "foobar \(\w\+\)" test.txt , я получаю все строки, которые соответствуют всему регулярному выражению, а не просто «слово после foobar»:

 foobar bash 1 foobar happy 

Я бы предпочел, чтобы результат этой команды выглядел так:

 bash happy 

Есть ли способ сообщить grep выводить элементы, которые соответствуют группировке (или определенной группе) в регулярном выражении?

  • Как «grep» для длины строки * not * в заданном диапазоне?
  • Заменить шаблон в файле с шаблоном во втором файле
  • Grep точное количество цифр и некоторые другие символы
  • Удалите строку, используя определенные значения (-)
  • Grep текст, соответствующий шаблону
  • Возврат только части строки после соответствующего шаблона
  • Как удалить все числа, окруженные <>
  • wget on Centos 7 Terminal как загрузить только текст без кода стиля сайта
  • 5 Solutions collect form web for “Может ли grep выводить только указанные группы, которые соответствуют?”

    GNU grep имеет параметр -P для регулярных выражений в стиле perl, а параметр -o печатает только то, что соответствует шаблону. Их можно объединить, используя утверждения обхода (описанные в разделе Расширенные шаблоны в man-странице perlre ), чтобы удалить часть шаблона grep из того, что определено для соответствия для целей -o .

     $ grep -oP 'foobar \K\w+' test.txt bash happy $ 

    \K – это короткая форма (и более эффективная форма) (?<=pattern) которую вы используете как выражение с обратной связью с нулевой шириной перед текстом, который вы хотите вывести. (?=pattern) можно использовать в качестве подтверждения с нулевой шириной после текста, который вы хотите вывести.

    Например, если вы хотите совместить слово между foo и bar , вы можете использовать:

     $ grep -oP 'foo \K\w+(?= bar)' test.txt 

    или (для симметрии)

     $ grep -oP '(?<=foo )\w+(?= bar)' test.txt 

    Стандартный grep не может этого сделать, но последние версии GNU grep могут . Вы можете обратиться к sed, awk или perl. Вот несколько примеров, которые делают то, что вы хотите на своем примере ввода; они ведут себя немного по-разному в угловых случаях.

    Замените foobar word other stuff word , напечатайте, только если замена выполнена.

     sed -n -e 's/^foobar \([[:alnum:]]\+\).*/\1/p' 

    Если первое слово является foobar , напечатайте второе слово.

     awk '$1 == "foobar" {print $2}' 

    Полоса foobar если это первое слово, и пропустите линию иначе; затем разделите все после первого пробела и распечатайте.

     perl -lne 's/^foobar\s+// or next; s/\s.*//; print' 

    Ну, если вы знаете, что foobar всегда является первым словом или линией, вы можете использовать разрез. Вот так:

     grep "foobar" test.file | cut -d" " -f2 
      sed -n "s/^.*foobar\s*\(\S*\).*$/\1/p" -n suppress printing s substitute ^.* anything before foobar foobar initial search match \s* any white space character (space) \( start capture group \S* capture any non-white space character (word) \) end capture group .*$ anything after the capture group \1 substitute everything with the 1st capture group p print it 

    Если PCRE не поддерживается, вы можете добиться того же результата с помощью двух вызовов grep. Например, чтобы захватить слово после foobar, выполните следующее:

     <test.txt grep -o 'foobar *[^ ]*' | grep -o '[^ ]*$' 

    Это можно развернуть до произвольного слова после foobar, как это (с ERE для удобочитаемости):

     i=1 <test.txt egrep -o 'foobar +([^ ]+ +){'$i'}[^ ]+' | grep -o '[^ ]*$' 

    Вывод:

     1 

    Обратите внимание, что индекс i основан на нуле.

    Linux и Unix - лучшая ОС в мире.