Wie grep ich Linien nach einem bestimmten Muster?

8

Angenommen, ich habe eine Datei mit den folgenden zwei Zeilen:

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

Ich brauche nur die Zeile mit dem Muster /aa/bbbb/cccccc, ich brauche nicht die zweite Zeile mit zusätzlichen Zeichen, dh ?dddddddd. Jetzt, als ich es versuchte

grep '/aa/bbbb/cccccc' file

Dann werden beide Zeilen ausgewählt. Ich brauche die volle Linie, grep -okönnte also keine Lösung sein.

Was könnte die mögliche Lösung mit grep sein, damit nur die erste Zeile basierend auf dem Suchmuster ausgewählt wird?

heemayl
quelle

Antworten:

7

Versuchen Sie den folgenden Befehl grep, der den Parameter -P( Perl-regexp ) verwendet.

grep -P '(?<!\S)/aa/bbbb/cccccc(?!\S)' file
  • (?<!\S)Dieser negative Lookbehind behauptet, dass das Zeichen, das der Zeichenfolge vorausgeht /aa/bbbb/cccccc, ein beliebiges, aber kein Leerzeichen ist.

  • (?!\S) Ein negativer Lookahead behauptet, dass das Zeichen nach dem Match ein beliebiges, aber kein Leerzeichen ist.

Noch ein grep,

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

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

Speichern Sie den obigen Code in einer Datei und benennen Sie ihn als script.py. Führen Sie dann das obige Skript mit aus

python3 script.py /path/to/the/file/you/want/to/work/with
Avinash Raj
quelle
Danke, Mann. Übrigens kann dies mit normalem / erweitertem Regex anstelle von Perl-Regex erfolgen?
Heemayl
1
Wie Terdon geschrieben hat, könnte man einfachgrep '/aa/bbbb/cccccc ' file
Avinash Raj
Die obigen Angaben drucken jedoch nicht die Zeilen, die nur eine /aa/bbbb/ccccccZeichenfolge enthalten.
Avinash Raj
Sie können das auch mitgrep -E '/aa/bbbb/cccccc(\s+|$)' file
terdon
Ja, sogrep -E '(^|\s)/aa/bbbb/cccccc(\s|$)' file
Avinash Raj
10

Am einfachsten ist es, nach dem Muster ein Leerzeichen einzufügen:

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

Oder, um alle Arten von Leerzeichen abzugleichen:

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

Oder

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

Oder mit einem positiven Lookahead :

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

Oder mit einem negativen Lookahead :

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

Oder Sie können das Spiel umkehren:

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

Oder um auch Linien abzugleichen, die nur Ihr Muster enthalten (kein nachfolgendes Leerzeichen):

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

Oder Sie können einfach ein kleines Skript verwenden:

  • In awk:

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

    Oder wenn Sie nicht wissen, in welchem ​​Feld sich Ihr Muster befindet

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

    $ perl -ane 'print if grep {$_ eq "/aa/bbbb/cccccc"} @F' file
    2014-05-05      09:11:53    /aa/bbbb/cccccc             29899
    
Terdon
quelle
@terdon, grep -v 'c?' filewarum Sie nicht verwenden, grep -v '?' fileweil die Datei nur zwei Zeilen enthält.
αғsнιη
@ KasiyA stimmt, ich wollte nur ein bisschen vom Muster behalten. Sie haben jedoch recht, in diesem speziellen Fall grep -v '?'wäre es genug.
Terdon
2

Zur Ergänzung @AvinashRaj ‚s Antwort , können Sie auch wie dieser Befehl verwenden.

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