Como grep linhas, com base em um determinado padrão?

8

Digamos que eu tenho um arquivo contendo as seguintes duas linhas:

2014-05-05      09:11:53    /aa/bbbb/cccccc             29899
2014-05-05      09:12:17    /aa/bbbb/cccccc?dddddddd    16767 

Eu preciso pegar a linha que contém /aa/bbbb/ccccccapenas o padrão , não preciso da segunda linha que contém caracteres extras, ou seja ?dddddddd. Agora, quando eu tentei

grep '/aa/bbbb/cccccc' file

Em seguida, as duas linhas estão sendo selecionadas. Eu preciso da linha completa, então grep -onão poderia ser uma solução.

Qual poderia ser a solução possível usando grep, para que apenas a primeira linha seja selecionada com base no padrão de pesquisa?

heemail
fonte

Respostas:

7

Experimente o comando grep abaixo, que usa o parâmetro -P( Perl-regexp ).

grep -P '(?<!\S)/aa/bbbb/cccccc(?!\S)' file
  • (?<!\S)Este lookbehind negativo afirma que o caractere que precede a string /aa/bbbb/ccccccseria qualquer, mas não um caractere não espacial.

  • (?!\S) O lookahead negativo afirma que o caractere após a correspondência seria qualquer, mas não um caractere não espacial.

Outro grep,

 grep -E '(^|\s)/aa/bbbb/cccccc(\s|$)' file

Através do python,

script.py

#!/usr/bin/python3
import re
import sys
file = sys.argv[1]
with open(file, 'r') as f:
    for line in f:
        for i in line.split():
            if i == "/aa/bbbb/cccccc":
                print(line, end='')

Salve o código acima em um arquivo e nomeie-o como script.py. Em seguida, execute o script acima,

python3 script.py /path/to/the/file/you/want/to/work/with
Avinash Raj
fonte
Obrigado cara. Btw isso pode ser feito usando regex normal / estendido em vez de regex perl?
heemayl
1
como terdon publicado, você poderia simplesmentegrep '/aa/bbbb/cccccc ' file
Avinash Raj
Mas o acima não imprimirá as linhas que possuem apenas /aa/bbbb/ccccccstring.
Avinash Raj
Você pode combinar isso também comgrep -E '/aa/bbbb/cccccc(\s+|$)' file
terdon 16/11/2012
sim, assimgrep -E '(^|\s)/aa/bbbb/cccccc(\s|$)' file
Avinash Raj 17/11
10

A maneira mais simples seria adicionar um espaço após o seu padrão:

$ grep '/aa/bbbb/cccccc ' file
2014-05-05      09:11:53    /aa/bbbb/cccccc             29899

Ou, para corresponder a todos os tipos de espaço em branco:

$ grep  '/aa/bbbb/cccccc[[:space:]]' file
2014-05-05      09:11:53    /aa/bbbb/cccccc             29899

Ou

$ grep -P '/aa/bbbb/cccccc\s+' file
2014-05-05      09:11:53    /aa/bbbb/cccccc             29899

Ou, com uma aparência positiva :

$ grep -P '/aa/bbbb/cccccc(?=\s)' file
2014-05-05      09:11:53    /aa/bbbb/cccccc             29899

Ou, com uma aparência negativa :

$ grep -P '/aa/bbbb/cccccc(?!\S)' file
2014-05-05      09:11:53    /aa/bbbb/cccccc             29899

Ou você pode reverter a partida:

$ grep  -v 'c?' file
2014-05-05      09:11:53    /aa/bbbb/cccccc             29899

Ou, para também corresponder às linhas que não contêm nada além do seu padrão (sem espaços em branco à direita):

grep -P '/aa/bbbb/cccccc(\s+|$)' file 
grep -E '/aa/bbbb/cccccc(\s+|$)' file 

Ou, você pode apenas usar um pequeno script:

  • No awk:

    $ awk '$3=="/aa/bbbb/cccccc"' file
    2014-05-05      09:11:53    /aa/bbbb/cccccc             29899
    

    Ou, se você não souber em qual campo seu padrão está

    $ awk '{for(i=1;i<=NF;i++){if($i=="/aa/bbbb/cccccc"){print}}}' file
    2014-05-05      09:11:53    /aa/bbbb/cccccc             29899
    
  • Em Perl

    $ perl -ane 'print if grep {$_ eq "/aa/bbbb/cccccc"} @F' file
    2014-05-05      09:11:53    /aa/bbbb/cccccc             29899
    
Terdon
fonte
@terdon grep -v 'c?' fileporque você não usa grep -v '?' fileporque o arquivo tem apenas duas linhas.
αғsнιη
@ KasiyA verdade, eu só queria manter um pouco do padrão. Você está certo, porém, neste caso em particular, grep -v '?'seria suficiente.
terdon
2

Para complementar a resposta de @AvinashRaj , você também pode usar o comando como este.

grep -P '/a+/b+/c+(?!\S)' file
αғsнιη
fonte