Como pesquisar a ocorrência de uma palavra e a ausência de outra usando grep

0

Eu tenho um arquivo com conteúdo semelhante a:

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

O número de colunas não é fixo. Mas a primeira coluna é uma URL, a segunda é um número, a forma inicial, a terceira, são palavras-chave separadas por vírgulas, mas elas variam de site para outro.

Eu quero contar o número de URLs (linhas) onde posso controlar quais palavras-chave estão na linha. Por exemplo,
1) AB+CD sem nonAB e nonCD . Nota: a palavra AB + CD pode ocorrer muitas vezes. 2) AB + CD sem ocorrência de nonCD (mas tudo bem se houver mais alguma coisa)

Como procurar por uma string em uma linha E garantir a ausência de outra string. Quando eu uso:

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

Imprime todas as linhas onde 'AB + CD' é encontrado.

E se eu quiser imprimir a linha onde há apenas 'AB + CD' para obter:

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

Ou há 'AB + CD' com qualquer outra coisa exceto 'nonAB' para obter:

youtube.com,9,AB+CD,AB+CD
facebook.com,20,AB+CD,nonCD
    
por user9371654 08.06.2018 / 06:54

3 respostas

5

Se você quiser apenas uma pesquisa de texto simples sem se preocupar com colunas, pode encadear a correspondência invertida grep -v da seguinte forma:

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

Se você quiser fazer a filtragem adequada por coluna, você deve usar algo como awk .

    
por 08.06.2018 / 07:46
4

Dicas gerais:

  1. Linhas contendo foo mais linhas contendo bar ( foo OR bar ):

    grep -e foo -e bar
    
  2. Linhas contendo foo e bar na mesma linha ( foo AND bar ):

    grep foo | grep bar
    
  3. Linhas que não contêm baz ( NOT baz ):

    grep -v baz
    

Com esses tijolos, você pode construir sua lógica. O problema é -v não está restrito a um único padrão, é global para todo o grep (pelo menos no meu Debian). Isso torna NOT (foo OR bar) possível:

grep -v -e foo -e bar

que é equivalente a (NOT foo) AND (NOT bar) :

grep -v foo | grep -v bar

No entanto, NOT (foo AND bar) (logicamente equivalente a (NOT foo) OR (NOT bar) ) não é tão fácil. Podemos tentar obter foo AND bar com um single (estendido) grep :

  1. Novamente linhas contendo foo e bar na mesma linha ( foo AND bar ):

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

Agora, obtenha NOT (foo AND bar) :

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

Não tenho certeza se o acima é um sistema completo ao lidar com mais de dois padrões. Ainda alguns dos seus problemas são solucionáveis com isso. Exemplo:

AB+CD without nonAB and nonCD

Se eu acertar você, é AB+CD AND NOT (nonAB OR nonCD)

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

Observe que essa solicitação dificulta as coisas:

I want to print the line where there is only 'AB+CD'

Pode-se dizer que grep ,AB+CD,AB+CD serve, mas como "o número de colunas não é fixo", acho que você gostaria de separar essas duas linhas:

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

Nesses casos, você precisa de expressões regulares mais complicadas ou de outras ferramentas (como awk ).

    
por 08.06.2018 / 07:50
1

Enquanto você receberá uma resposta aqui, você deve dar uma olhada em homem grep (pode ser esmagadora) e alguns exemplos . Por enquanto, aqui vai a resposta:

Usando grep

grep "foobar" test.txt

pesquisará linhas com a palavra foobar no arquivo test.txt e exibirá todas as ocorrências,

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

pesquisará linhas com a palavra foo , mas não bar . Recebemos isso por causa do -v switch para o qual o manpage explica:

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

Significa simplesmente que ele irá procurar por linhas com essas palavras (aqui bar ), mas irá excluí-las na exibição final. Assim, invertendo a pesquisa .

Além disso, para contar o número de linhas que correspondem à pesquisa, use o interruptor -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 .)

Como se exercitar, experimente as pesquisas grep no arquivo foobar .

A resposta

Pesquise AB+CD ignorando nonAB e nonCD e conte os URLs:

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

em que -v "non" simplesmente ignorará os nonAB e nonCD , pois ambos têm non neles. E -c dará contagem total para as correspondências em vez de imprimi-las. Para imprimir linhas de correspondência, ignore apenas -c .

Você pode usá-lo para invertidos separados:

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

em que \| representa OR e significa% da palavra nonAB ou nonCD exata especificada pela opção -e .

Aconselhamos você a ver a resposta de Kamil , ler manpages (você sabe o comando) o máximo que puder, tentar com afinco enquanto procura coisas online & servir a comunidade. Sinta-se à vontade para adicionar mais detalhes para responder.

    
por 08.06.2018 / 07:49