2016-10-01 2 views
0

Mit Shell möchte ich nur Sub-String mit dem nächsten Wort zu diesem Sub-String suchen und drucken.Wie extrahiert man ein Wort aus grep in der Shell?

z.B. Logfile hat Zeile "Heute ist Montag und das ist: 1234, also bin ich in."

if grep -q "this is :" ./logfile; then 
    #here i want to print only sub-string with next word i.e. "this is:1234" 
    #echo ??? 
fi 
+0

Wie lange einer Datei? Wenn es kurz ist, kann es schneller sein, diese Suche in der nativen Shell zu machen, anstatt externe Tools zu erzeugen ('grep',' sed', 'awk', usw.), obwohl diese Werkzeuge den Inhalt im Allgemeinen schneller verarbeiten als die Kosten, um sie zu starten up ist bezahlt. –

+0

BTW, das äußere 'if grep -q' ist wohl eine schlechte Idee - bedeutet, dass Sie die Datei zweimal lesen, einmal, um ihren Inhalt zu überprüfen, und dann wieder, um ihren Inhalt zu lesen. Wenn Sie einen externen Befehl ausführen, verwenden Sie besser if result = $ (that-command); dann ... 'um sowohl die Ausgabe zu erfassen als auch den Exit-Status in einem Durchgang zu prüfen. Wenn der Befehl den Exit-Status nicht basierend darauf festlegt, ob es eine Übereinstimmung gibt, dann ist 'if result = $ (that-Befehl) && [-n" $ result "]; dann kann es mehr Sinn ergeben. –

Antwort

0

Sie können einen regulären Ausdruck mit einem look-behind verwenden, wenn Sie das nächste Wort wollen:

$ grep --perl-regexp -o '(?<=(this is:))(\S+)' ./logfile 
1234 

Wenn Sie beide wollen, dann nur:

$ grep --perl-regexp -o 'this is:\S+' ./logfile 
this is:1234 

Die -o Option weist grep an, nur das übereinstimmende Teil zurückzugeben.

In den obigen Befehlen haben wir angenommen, dass ein "Wort" eine Folge von Nicht-Leerzeichen-Zeichen ist. Sie können das nach Ihren Bedürfnissen anpassen.

sed 's/.*\(this is:[0-9a-zA-Z]*\).*/\1/' logfile 

EDIT: Der obige Befehl ist nur gut für 1 Line-Eingang in \(..\)

1

Sie können sed mit \1 verwenden, um den gefundenen String angezeigt werden soll.

Wenn Sie eine Datei mit mehr Zeilen haben, möchten Sie nur die Zeilen drucken, die entsprechen:

sed -n 's/.*\(this is:[0-9a-zA-Z]*\).*/\1/p' logfile 

Wenn Sie eine große Datei haben und wollen nur das erste Spiel, um zu sehen, können Sie diesen Befehl kombiniert werden mit head -1, aber Sie möchten nach der ersten Übereinstimmung aufhören zu scannen/zu analysieren. Sie können q verwenden, um zu beenden, aber Sie möchten nur nach einer Übereinstimmung beenden.

sed -n '/.*\(this is:[0-9a-zA-Z]*\).*/{s//\1/p;q}' 
+0

Wenn Sie dies geändert haben, um auch alle anderen Zeilen zu eliminieren und nach dem Finden eines Matches zu beenden, würde ich denken, dass wir eingestellt sind. –

+0

@Charles: Überprüfen. –

+0

Sieht gut aus für mich. –

0

Sie alles sehen können bis zu, aber nicht einschließlich der nächsten Raum wie folgt aus:

Die [] stellt die Zeichen an, die Sie suchen und die ^ zu Beginn der Ergänzung set, also ist die Menge der Zeichen, die Sie suchen, ein Leerzeichen, aber ergänzt, dh kein Leerzeichen. Die + sagt, dass es mindestens ein oder mehrere solcher Zeichen geben muss.

Die -E sagt grep, erweiterte reguläre Ausdrücke zu verwenden, und die -o bedeutet, nur den übereinstimmenden Teil zu drucken.

+0

Ich würde vorschlagen, '[^ [: space:]]' 'zu verwenden, um auch auf Tab-Zeichen & c zu stoppen. –

+0

@CharlesDuffy Ja, das ist eine deutliche Verbesserung - danke. –

0

Wenn Sie ein System mit GNU-Erweiterungen (aber nicht sicher sind, es mit optionaler PCRE-Unterstützung kompiliert wurde), betrachten:

if result=$(grep -E -m 1 -o 'this is:[^[:space:]]+' logfile); then 
    echo "value is: ${result#*:}" 
fi 

${varname#value} auf den Inhalt varname erweitert, sondern mit value aus dem gestrippt Anfang wenn vorhanden. Somit streift ${result#*:} alles bis zum ersten Doppelpunkt in result.

Dies funktioniert jedoch möglicherweise nicht auf Systemen ohne die Nicht-POSIX-Optionen -o oder -m.


Wenn Sie nicht-GNU-Systeme zu unterstützen, ist awk ein Werkzeug einer Überlegung wert: Im Gegensatz zu Antworten erfordern nonportable Erweiterungen (wie grep -P), das auf jeder moderne Plattform awk (getestet mit GNU awk, die letzten BSD arbeiten sollte und mawk, auch keine Warnungen mit mit gawk --posix --lint):

# note that the constant 8 is the length of "this is:" 
# GNU awk has cleaner syntax, but trying to be portable here. 
if value=$(awk ' 
    BEGIN { matched=0; }  # by default, this will trigger END to exit as failure 
    /this is:/ { 
    match($0, /this\ is:([^[:space:]]+)/); 
    print substr($0, RSTART+8, RLENGTH-8); 
    matched=1;    # tell END block to use zero exit status 
    exit(0);    # stop processing remaining file contents, jump to END 
    } 
    END { if(matched == 0) { exit(1); } } 
'); then 
    echo "Found value of $value" 
else 
    echo "Could not find $value in file" 
fi 
Verwandte Themen