Angenommen, ich habe eine Datei:
# file: 'test.txt'
foobar bash 1
bash
foobar happy
foobar
Ich möchte nur wissen, welche Wörter nach "foobar" erscheinen, damit ich diese Regex verwenden kann:
"foobar \(\w\+\)"
Die Klammern zeigen an, dass ich ein besonderes Interesse an dem Wort direkt nach foobar habe. Wenn ich jedoch grep "foobar \(\w\+\)" test.txt
ausführe, erhalte ich die gesamten Zeilen, die mit der gesamten Regex übereinstimmen, und nicht nur "das Wort nach foobar":
foobar bash 1
foobar happy
Ich würde es viel lieber sehen, wenn die Ausgabe dieses Befehls so aussehen würde:
bash
happy
Gibt es eine Möglichkeit, grep anzuweisen, nur die Elemente auszugeben, die mit der Gruppierung (oder einer bestimmten Gruppierung) in einem regulären Ausdruck übereinstimmen?
GNU grep hat die Option -P
für Regexe im Perl-Stil und die Option -o
, um nur das auszugeben, was mit dem Muster übereinstimmt. Diese können unter Verwendung von Look-Around-Assertions (beschrieben unter Extended Patterns in der perlre manpage) kombiniert werden, um einen Teil des grep-Musters aus dem zu entfernen, was für die Zwecke von -o
als übereinstimmend bestimmt wird.
$ grep -oP 'foobar \K\w+' test.txt
bash
happy
$
Das \K
ist die Kurzform (und effizientere Form) von (?<=Pattern)
, die Sie als eine Null-Breite Look-Behind-Assertion vor dem auszugebenden Text verwenden. (?=pattern)
kann als Vorausschau-Assertion mit Null-Breite nach dem auszugebenden Text verwendet werden.
Wenn Sie zum Beispiel das Wort zwischen "foo" und "bar" finden wollen, können Sie das verwenden:
$ grep -oP 'foo \K\w+(?= bar)' test.txt
oder (zur Symmetrie)
$ grep -oP '(?<=foo )\w+(?= bar)' test.txt
Standard grep kann das nicht, aber neuere Versionen von GNU grep können das. Sie können sich an sed, awk oder perl wenden. Hier sind ein paar Beispiele, die das tun, was Sie mit Ihrer Beispieleingabe wollen; sie verhalten sich in den Ecken etwas anders.
Ersetze foobar word other stuff
durch word
, drucke nur, wenn eine Ersetzung erfolgt ist.
sed -n -e 's/^foobar \([[:alnum:]]\+\).*/\1/p'
Wenn das erste Wort Foobar
ist, drucke das zweite Wort.
awk '$1 == "foobar" {print $2}'
Entferne foobar
, wenn es das erste Wort ist, und überspringe die Zeile sonst; dann entferne alles nach dem ersten Leerzeichen und drucke.
perl -lne 's/^foobar\s+// or next; s/\s.*//; print'