Может ли grep показывать только те слова, которые соответствуют шаблону поиска? - PullRequest
578 голосов
/ 10 октября 2009

Есть ли способ заставить grep выводить "слова" из файлов, которые соответствуют поисковому выражению?

Если я хочу найти все экземпляры, скажем, «th» в нескольких файлах, я могу сделать:

grep "th" *

но вывод будет что-то вроде (жирным шрифтом от меня);

some-text-file : <b>the</b> cat sat on <b>the</b> mat  
some-other-text-file : <b>the</b> quick brown fox  
yet-another-text-file : i hope <b>this</b> explains it <b>thoroughly</b> 

То, что я хочу вывести, используя тот же поиск:

the
the
the
this
thoroughly

Возможно ли это с помощью grep? Или используя другую комбинацию инструментов?

Ответы [ 14 ]

798 голосов
/ 10 октября 2009

Попробуйте grep -o

grep -oh "\w*th\w*" *

Редактировать: в соответствии с комментариями Фила

С Документы :

-h, --no-filename
    Suppress the prefixing of file names on output. This is the default
    when there is only  one  file  (or only standard input) to search.
-o, --only-matching
    Print  only  the matched (non-empty) parts of a matching line,
    with each such part on a separate output line.
76 голосов
/ 14 апреля 2013

Ответ перекрестного распределения (включая окна minGW?)

grep -h "[[:alpha:]]*th[[:alpha:]]*" 'filename' | tr ' ' '\n' | grep -h "[[:alpha:]]*th[[:alpha:]]*"

Если вы используете более старые версии grep (например, 2.4.2), который не включает опцию -o. Используйте вышеупомянутое. Еще используйте более простую версию для поддержки ниже.

Ответ о перекрестном распространении Linux

grep -oh "[[:alpha:]]*th[[:alpha:]]*" 'filename'

Для суммирования -oh выводит совпадения регулярного выражения с содержимым файла (а не с именем файла), так же, как вы ожидаете, что регулярное выражение будет работать в vim / etc ... Какое слово или регулярное выражение вы будете искать тогда это зависит от вас! Пока вы остаетесь в POSIX, а не в синтаксисе perl (см. Ниже)

Больше из руководства по grep

-o      Print each match, but only the match, not the entire line.
-h      Never print filename headers (i.e. filenames) with output lines.
-w      The expression is searched for as a word (as if surrounded by
         `[[:<:]]' and `[[:>:]]';

Причина, по которой оригинальный ответ не работает для всех

Использование \w варьируется от платформы к платформе, так как это расширенный синтаксис "perl". Таким образом, те установки grep, которые ограничены для работы с классами символов POSIX, используют [[:alpha:]], а не его perl-эквивалент \w. Подробнее о 1030 *

см. На странице Википедии о регулярном выражении.

В конечном счете, ответ POSIX выше будет намного более надежным независимо от платформы (являющейся оригинальной) для grep

Что касается поддержки grep без опции -o, первый grep выводит соответствующие строки, tr разделяет пробелы на новые строки, окончательный grep фильтрует только соответствующие строки.

(PS: я знаю, что большинство платформ к настоящему времени было бы исправлено для \ w ...., но всегда есть те, которые отстают)

Кредит для обхода "-o" от ответа @AdamRosenfield

41 голосов
/ 10 октября 2009

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

cat * | tr ' ' '\n' | grep th
35 голосов
/ 10 октября 2009

Просто awk, комбинация инструментов не нужна.

# awk '{for(i=1;i<=NF;i++){if($i~/^th/){print $i}}}' file
the
the
the
this
thoroughly
26 голосов
/ 28 марта 2017

Это проще, чем вы думаете. Попробуйте это:

egrep -wo 'th.[a-z]*' filename.txt #### (Case Sensitive)

egrep -iwo 'th.[a-z]*' filename.txt  ### (Case Insensitive)

Где,

 egrep: Grep will work with extended regular expression.
 w    : Matches only word/words instead of substring.
 o    : Display only matched pattern instead of whole line.
 i    : If u want to ignore case sensitivity.
10 голосов
/ 29 ноября 2012
Команда

grep только для сопоставления и perl

grep -o -P 'th.*? ' filename
8 голосов
/ 12 января 2011

Я был недоволен трудно запоминающимся синтаксисом awk, но мне понравилась идея использовать одну утилиту для этого.

Кажется, что ack (или ack-grep, если вы используете Ubuntu) может легко это сделать:

# ack-grep -ho "\bth.*?\b" *

the
the
the
this
thoroughly

Если вы опустите флаг -h, вы получите:

# ack-grep -o "\bth.*?\b" *

some-other-text-file
1:the

some-text-file
1:the
the

yet-another-text-file
1:this
thoroughly

В качестве бонуса вы можете использовать флаг --output, чтобы сделать это для более сложных поисков с почти самым простым синтаксисом, который я нашел:

# echo "bug: 1, id: 5, time: 12/27/2010" > test-file
# ack-grep -ho "bug: (\d*), id: (\d*), time: (.*)" --output '$1, $2, $3' test-file

1, 5, 12/27/2010
8 голосов
/ 14 сентября 2010
cat *-text-file | grep -Eio "th[a-z]+"
4 голосов
/ 16 января 2014

Для поиска всех слов, начинающихся с «icon-», следующая команда работает отлично. Я использую Ack здесь, который похож на grep, но с лучшими параметрами и хорошим форматированием.

ack -oh --type=html "\w*icon-\w*" | sort | uniq
3 голосов
/ 14 февраля 2013

У меня была похожая проблема, я искал в регулярном выражении grep / pattern и "найден соответствующий шаблон".

В конце я использовал egrep (то же самое регулярное выражение для grep -e или -G не дало мне того же результата egrep) с опцией -o

Итак, я думаю, что это может быть что-то похожее (я НЕ мастер регулярных выражений):

egrep -o "the*|this{1}|thoroughly{1}" filename
...