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 diesen regulären Ausdruck verwenden kann:
"foobar \(\w\+\)"
Die Klammern zeigen an, dass ich ein besonderes Interesse an dem Wort direkt nach foobar habe. Aber wenn ich a mache grep "foobar \(\w\+\)" test.txt
, bekomme ich die ganzen Zeilen, die dem gesamten regulären Ausdruck entsprechen, und nicht nur "das Wort nach foobar":
foobar bash 1
foobar happy
Ich würde es sehr bevorzugen, wenn die Ausgabe dieses Befehls so aussähe:
bash
happy
Gibt es eine Möglichkeit, grep anzuweisen, nur die Elemente auszugeben, die der Gruppierung (oder einer bestimmten Gruppierung) in einem regulären Ausdruck entsprechen?
text-processing
grep
regular-expression
Cory Klein
quelle
quelle
perl -lne 'print $1 if /foobar (\w+)/' < test.txt
Antworten:
GNU grep bietet die
-P
Option für reguläre Ausdrücke im Perl-Stil und die-o
Option, nur das zu drucken, was dem Muster entspricht. Diese können mit Hilfe von Look-Around-Behauptungen (beschrieben unter Erweiterte Muster in der Perlre-Manpage ) kombiniert werden, um einen Teil des Grep- Musters von dem zu entfernen, für den eine Übereinstimmung festgestellt wurde-o
.Dies
\K
ist die Kurzform (und effizientere Form),(?<=pattern)
die Sie als Look-Behind-Behauptung ohne Breite vor dem auszugebenden Text verwenden.(?=pattern)
kann als Look-Ahead-Behauptung mit der Breite Null nach dem auszugebenden Text verwendet werden.Wenn Sie beispielsweise das Wort zwischen
foo
undbar
zuordnen möchten, können Sie Folgendes verwenden:oder (aus Symmetriegründen)
quelle
sed(1)
grep -oP 'foobar \K\w+' test.txt
mit den OP's nichts ausgegeben wirdtest.txt
. Die Grep-Version ist 2.5.1. Was könnte falsch sein? O_OStandard grep kann dies nicht, aber die neuesten Versionen von GNU grep können dies . Sie können sich an sed, awk oder perl wenden. Hier sind einige Beispiele, die das tun, was Sie von Ihrer Beispieleingabe erwarten. Sie verhalten sich in Eckfällen etwas anders.
Ersetzen
foobar word other stuff
durchword
, nur drucken, wenn ein Ersatz erfolgt ist.Wenn das erste Wort ist
foobar
, drucken Sie das zweite Wort.Streifen Sie ab,
foobar
wenn es das erste Wort ist, und überspringen Sie die Zeile ansonsten. Dann alles nach dem ersten Leerzeichen entfernen und ausdrucken.quelle
grep
. Aber die Syntax für diese Befehle kommt mir bekannt vor, da ich mit Suchen & Ersetzen + Regexen im Vim-Stil vertraut bin. Danke vielmals.grep
keine PCRE-Unterstützung bietet.quelle
^
und$
sind irrelevant, da.*
es sich um ein gieriges Match handelt. Das Einbeziehen dieser Elemente kann jedoch hilfreich sein, um die Absicht des regulären Ausdrucks zu klären.Wenn Sie wissen, dass foobar immer das erste Wort oder die erste Zeile ist, können Sie cut verwenden. Wie so:
quelle
-o
Aktivierung von grep ist weit verbreitet (mehr als die Gnu-grep-Erweiterungen). Dadurchgrep -o "foobar" test.file | cut -d" " -f2
wird die Effektivität dieser Lösung erhöht, die portabler ist als die Verwendung von Lookbehind-Assertions.grep -o "foobar .*
"odergrep -o "foobar \w+"
.Wenn PCRE nicht unterstützt wird, können Sie mit zwei Aufrufen von grep dasselbe Ergebnis erzielen. Um beispielsweise das Wort nach foobar zu erfassen, gehen Sie wie folgt vor :
Dies kann nach foobar wie folgt zu einem beliebigen Wort erweitert werden (mit EREs zur besseren Lesbarkeit):
Ausgabe:
Beachten Sie, dass der Index auf
i
Null basiert.quelle
pcregrep
Mit einer intelligenteren-o
Option können Sie auswählen, welche Erfassungsgruppen ausgegeben werden sollen. Also, mit Ihrer Beispieldatei,quelle
Die Verwendung
grep
ist nicht plattformübergreifend, da-P
/--perl-regexp
nur unter GNUgrep
und nicht unter BSDgrep
verfügbar ist .Hier ist die Lösung mit
ripgrep
:Wie pro
man rg
:Verwandt: GH-462 .
quelle
Ich fand die Antwort von @jgshawkey sehr hilfreich.
grep
ist kein so gutes Werkzeug dafür, aber sed ist es, obwohl wir hier ein Beispiel haben, das grep verwendet, um eine relevante Zeile zu erfassen.Die Regex-Syntax von sed ist eigenwillig, wenn Sie nicht daran gewöhnt sind.
Hier ist ein weiteres Beispiel: Dieses analysiert die Ausgabe von xinput, um eine ID-Ganzzahl zu erhalten
und ich will 19
Beachten Sie die Klassensyntax:
und die Notwendigkeit, dem Folgenden zu entkommen
+
Ich gehe davon aus, dass nur eine Zeile passt.
quelle
grep
, vorausgesetzt 'TouchPad' steht links von 'id':echo "SynPS/2 Synaptics TouchPad id=19 [slave pointer (2)]" | sed -nE "s/.*TouchPad.+id=([0-9]+).*/\1/p"