Как найти вхождение слова и отсутствие другого с помощью grep

Как найти вхождение слова и отсутствие другого с помощью grep

У меня есть файл с содержимым, похожим на:

google.com,9,AB+CD,nonAB+nonCD
youtube.com,9,AB+CD,AB+CD
facebook.com,20,AB+CD,nonCD

Количество столбцов не фиксировано. Но первый столбец — это URL, второй — число, начиная с третьего — ключевые слова, разделенные запятыми, но они различаются от сайта к сайту.

Я хочу подсчитать количество URL-адресов (строк), где я могу контролировать, какие ключевые слова находятся в строке. Например,
1) AB+CDбез nonABи nonCD. Примечание: слово AB+CD может встречаться много раз. 2) AB+CD без вхождения nonCD(но это нормально, если есть что-то еще)

Как искать строку в строке И гарантировать отсутствие другой строки. Когда я использую:

grep 'AB+CD' test.txt > result.txt

Он выводит каждую строку, где встречается «AB+CD».

Что делать, если я хочу напечатать строку, в которой есть только «AB+CD», чтобы получить:

youtube.com,9,AB+CD,AB+CD

Или есть «AB+CD» с чем угодно, кроме «nonAB», чтобы получить:

youtube.com,9,AB+CD,AB+CD
facebook.com,20,AB+CD,nonCD

решение1

Если вам нужен просто текстовый поиск, не заботясь о столбцах, вы можете связать инвертированное соответствие grep -vследующим образом:

cat input.txt | grep 'IncludedText' | grep -v 'ExcludedText'

Если вы хотите выполнить правильную фильтрацию по столбцу, вам нужно будет использовать что-то вроде awk.

решение2

Общие приемы:

  1. Строки, содержащие fooплюс строки, содержащие bar( foo OR bar):

    grep -e foo -e bar
    
  2. Строки, содержащие fooи barв одной строке ( foo AND bar):

    grep foo | grep bar
    
  3. Строки, не содержащие baz( NOT baz):

    grep -v baz
    

С помощью этих кирпичиков вы можете построить свою логику. Проблема -vне ограничивается одним шаблоном, она глобальна для всего grep(по крайней мере, в моем Debian). Это делает NOT (foo OR bar)возможным:

grep -v -e foo -e bar

что эквивалентно (NOT foo) AND (NOT bar):

grep -v foo | grep -v bar

Однако NOT (foo AND bar)(логически эквивалентно (NOT foo) OR (NOT bar)) не так просто. Мы можем попытаться получить foo AND barс помощьюодинокий(расширенный) grep:

  1. Снова строки, содержащие fooи barв одной строке ( foo AND bar):

    grep -E 'foo.*bar|bar.*foo'
    

Теперь, чтобы получить NOT (foo AND bar):

grep -v -E 'foo.*bar|bar.*foo'

Я не уверен, что вышеизложенное является полной системой при работе с более чем двумя шаблонами. Тем не менее, некоторые из ваших проблем можно решить с его помощью. Пример:

AB+CDбез nonABиnonCD

Если я правильно понял, то этоAB+CD AND NOT (nonAB OR nonCD)

grep AB+CD | grep -v -e nonAB -e nonCD

Обратите внимание, что этот запрос все усложняет:

Я хочу напечатать строку, где есть только «AB+CD»

Можно сказать, grep ,AB+CD,AB+CDчто так и будет, но поскольку «количество столбцов не фиксировано», я думаю, вы захотите разделить эти две строки:

youtube.com,9,AB+CD,AB+CD,AB+CD
youtube.com,9,AB+CD,AB+CD,banana

В таких случаях вам понадобятся более сложные регулярные выражения или другие инструменты (например awk, ).

решение3

Пока вы получите ответ здесь, вам стоит взглянуть начеловек grep(может быть подавляющим) иНекоторые примеры. На данный момент вот ответ:

С использованиемgrep

grep "foobar" test.txt

будет искать строки, содержащие слово foobarв файле test.txt, и отображать все вхождения, тогда как ,

grep "foo" -v "bar" test.txt

будет искать строки, содержащие слово foo, но не bar. Мы получаем это из-за-vпереключатель, для которого страница руководства объясняет:

-v, --invert-match
    Invert the sense of matching, to select non-matching lines.
    (-v is specified by POSIX .)

Это просто означает, что он будет искать строки, содержащие эти слова (здесь bar), но исключит их из окончательного отображения. Таким образоминвертирование поиска.

Также, чтобы подсчитать количество строк, соответствующих поиску, используйте-cвыключатель :

-c, --count
    Suppress normal output; instead print a count of matching lines
    for each input file. With the -v, --invert-match option (see below),
    count non-matching lines. (-c is specified by POSIX .)

В качестве самостоятельного упражнения попробуйте выполнить поиск grep в файле.фубар.

Ответ

Поиск AB+CDигнорирования nonABи nonCDподсчета URL-адресов:

grep "AB+CD" test | grep -cve "non"

где -v "non"просто проигнорирует оба nonABи nonCDтак как они оба имеют nonв них. И -cдаст общее количество совпадений вместо их вывода. Чтобы вывести совпадающие строки, просто проигнорируйте -c.

Вы можете использовать его для отдельных инвертов:

grep "AB+CD" test | grep -cve "nonAB\|nonCD"

где \|представляет ORи означает либо nonABилиnonCD точныйслово, указанное-eвыключатель.


Посоветовал бы вамсм. ответ Камиля, читайте man-страницы (вы знаете команду) как можно больше, старайтесь изо всех сил, когда ищете информацию в Интернете и служите сообществу. Не стесняйтесь добавлять больше подробностей для ответа.

Связанный контент