Jak grepować linie na podstawie określonego wzoru?

8

Załóżmy, że mam plik zawierający następujące dwa wiersze:

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

Muszę uzyskać linię zawierającą /aa/bbbb/cccccctylko wzorzec , nie potrzebuję drugiej linii zawierającej dodatkowe znaki tj ?dddddddd. Teraz kiedy próbowałem

grep '/aa/bbbb/cccccc' file

Następnie wybierane są obie linie. Potrzebuję pełnej linii, więc grep -onie może być rozwiązania.

Jakie może być możliwe użycie grep, aby na podstawie wzorca wyszukiwania wybrana została tylko pierwsza linia?

heemayl
źródło

Odpowiedzi:

7

Wypróbuj poniższą komendę grep, która używa parametru -P( Perl-regexp ).

grep -P '(?<!\S)/aa/bbbb/cccccc(?!\S)' file
  • (?<!\S)Ten negatywny wygląd sugeruje, że znak poprzedzający łańcuch /aa/bbbb/ccccccbyłby dowolnym, ale nie spacją.

  • (?!\S) Negatywne spojrzenie wstecz zapewnia, że ​​znak po dopasowaniu byłby dowolnym, ale nie spacją.

Kolejny grep

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

Poprzez 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='')

Zapisz powyższy kod w pliku i nazwij go jako script.py. Następnie wykonaj powyższy skrypt za pomocą

python3 script.py /path/to/the/file/you/want/to/work/with
Avinash Raj
źródło
Dzięki stary. Btw można to zrobić przy użyciu normalnego / rozszerzonego wyrażenia regularnego zamiast wyrażenia regularnego Perl?
heemayl
1
jak napisał terdon, możesz po prostugrep '/aa/bbbb/cccccc ' file
Avinash Raj
Ale powyższe nie wypisze linii, które mają tylko /aa/bbbb/ccccccciąg znaków.
Avinash Raj
Możesz to również dopasować dogrep -E '/aa/bbbb/cccccc(\s+|$)' file
terdon
tak, takgrep -E '(^|\s)/aa/bbbb/cccccc(\s|$)' file
Avinash Raj
10

Najprostszym sposobem byłoby dodanie spacji po wzorze:

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

Lub, aby dopasować wszystkie rodzaje białych znaków:

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

Lub

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

Lub z pozytywnym spojrzeniem w przyszłość :

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

Lub z negatywnym spojrzeniem w przyszłość :

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

Lub możesz cofnąć dopasowanie:

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

Lub, aby dopasować również linie, które nie zawierają nic oprócz wzorca (bez spacji końcowych):

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

Lub możesz po prostu użyć małego skryptu:

  • W awk:

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

    Lub, jeśli nie wiesz, w którym polu znajduje się twój wzór

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

    $ perl -ane 'print if grep {$_ eq "/aa/bbbb/cccccc"} @F' file
    2014-05-05      09:11:53    /aa/bbbb/cccccc             29899
    
terdon
źródło
@terdon, grep -v 'c?' filedlaczego nie używasz, grep -v '?' fileponieważ plik ma tylko dwie linie.
αғsнιη
@ Kasiy: To prawda, chciałem zachować trochę wzorca. Masz jednak całkowitą rację, w tym konkretnym przypadku grep -v '?'wystarczy.
terdon