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

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

3 ответа3

5

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

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

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

4

Общие хитрости:

  1. Строки, содержащие строки foo plus, содержащие 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).

1

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

Используя grep

grep "foobar" test.txt

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

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

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

-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 в файле foobar.

Ответ

Найдите 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-страницы (вы знаете команду) как можно больше, стараться искать материалы в Интернете и обслуживать сообщество. Не стесняйтесь добавлять дополнительные детали, чтобы ответить.

Всё ещё ищете ответ? Посмотрите другие вопросы с метками .