Ich sehe viele Beispiele und Manpages, wie man Dinge wie Suchen und Ersetzen mit sed, awk oder gawk macht.
In meinem Fall habe ich jedoch einen regulären Ausdruck, den ich für eine Textdatei ausführen möchte, um einen bestimmten Wert zu extrahieren. Ich möchte nicht suchen und ersetzen. Dies wird von Bash aufgerufen. Verwenden wir ein Beispiel:
Beispiel für einen regulären Ausdruck:
.*abc([0-9]+)xyz.*
Beispiel für eine Eingabedatei:
a
b
c
abc12345xyz
a
b
c
So einfach das klingt, ich kann nicht herausfinden, wie man sed / awk / gawk richtig nennt. Was ich gehofft hatte, ist aus meinem Bash-Skript heraus:
myvalue=$( sed <...something...> input.txt )
Dinge, die ich versucht habe, sind:
sed -e 's/.*([0-9]).*/\\1/g' example.txt # extracts the entire input file
sed -n 's/.*([0-9]).*/\\1/g' example.txt # extracts nothing
Antworten:
Mein
sed
(Mac OS X) hat nicht funktioniert+
. Ich habe es*
stattdessen versucht und einp
Tag zum Drucken von Übereinstimmungen hinzugefügt :Für die Zuordnung von mindestens einem numerischen Zeichen ohne
+
würde ich Folgendes verwenden:quelle
+
und dann funktionierte es für mich:sed -n 's/^.*abc\([0-9]\+\)xyz.*$/\1/p'
Sie können sed verwenden, um dies zu tun
-n
Drucken Sie die resultierende Zeile nicht aus-r
Dies macht es so, dass Sie nicht die Flucht der Capture Group Parens haben()
.\1
die Erfassungsgruppenübereinstimmung/g
globales Spiel/p
Drucken Sie das ErgebnisIch habe mir ein Tool geschrieben , das das einfacher macht
quelle
Ich
perl
mache es mir leichter. z.BDadurch wird Perl ausgeführt. Die
-n
Option weist Perl an, jeweils eine Zeile von STDIN einzulesen und den Code auszuführen. Die-e
Option gibt die auszuführende Anweisung an.Die Anweisung führt einen regulären Ausdruck in der gelesenen Zeile aus, und wenn er übereinstimmt, wird der Inhalt des ersten Satzes von Klammern (
$1
) ausgedruckt .Sie können dies tun, um mehrere Dateinamen am Ende auch. z.B
perl -ne 'print $1 if /.*abc([0-9]+)xyz.*/' example1.txt example2.txt
quelle
Wenn Ihre Version dies
grep
unterstützt, können Sie die-o
Option verwenden, um nur den Teil einer Zeile zu drucken , der Ihrem regulären Ausdruck entspricht.Wenn nicht, dann ist hier das Beste, was
sed
ich mir vorstellen kann:... die ohne Ziffern löscht / überspringt und für die verbleibenden Zeilen alle führenden und nachfolgenden nichtstelligen Zeichen entfernt. (Ich vermute nur, dass Sie beabsichtigen, die Nummer aus jeder Zeile zu extrahieren, die eine enthält).
Das Problem mit so etwas wie:
.... oder
...
sed
unterstützt nur "gierige" Übereinstimmungen ... also stimmt die erste. * mit dem Rest der Zeile überein. Solange wir keine negierte Zeichenklasse verwenden können, um eine nicht gierige Übereinstimmung zu erzielen ... oder eine Versionsed
mit Perl-kompatiblen oder anderen Erweiterungen der regulären Ausdrücke, können wir keine genaue Musterübereinstimmung mit dem Musterraum (einer Linie) extrahieren ).quelle
sed
Befehle folgendermaßen kombinieren :sed -n 's/[^0-9]*\([0-9]\+\).*/\1/p'
grep -o
! Ich habe versucht, dies zu tun,sed
und hatte Probleme damit, in einigen Zeilen mehrere Übereinstimmungen zu finden. Meine Lösung ist stackoverflow.com/a/58308239/117471Sie können
awk
mit verwenden,match()
um auf die erfasste Gruppe zuzugreifen:Dies versucht, dem Muster zu entsprechen
abc[0-9]+xyz
. In diesem Fall werden die Slices im Array gespeichertmatches
, dessen erstes Element der Block ist[0-9]+
. Damatch()
die Zeichenposition oder der Index zurückgegeben wird, an dem diese Teilzeichenfolge beginnt (1, wenn sie am Anfang der Zeichenfolge beginnt) , wird dieprint
Aktion ausgelöst.Mit können
grep
Sie einen Blick zurück und einen Blick nach vorne werfen:Diese prüft das Muster ,
[0-9]+
wenn es auftritt innerhalbabc
undxyz
und druckt nur die Ziffern.quelle
Perl ist die sauberste Syntax, aber wenn Sie kein Perl haben (ich verstehe, nicht immer da), ist die einzige Möglichkeit, Gawk und Komponenten eines regulären Ausdrucks zu verwenden, die Verwendung der Gensub-Funktion.
Die Ausgabe der Beispiel-Eingabedatei erfolgt
Hinweis: gensub ersetzt den gesamten regulären Ausdruck (zwischen dem //), daher müssen Sie das. * Vor und nach dem ([0-9] +) setzen, um Text vor und nach der Zahl in der Ersetzung zu entfernen.
quelle
match()
auf die erfassten Gruppen zuzugreifen. Siehe meine Antwort dazu.Wenn Sie Linien auswählen möchten, entfernen Sie die nicht gewünschten Bits:
Grundsätzlich werden die gewünschten Zeilen ausgewählt
egrep
und anschließendsed
die Bits vor und nach der Nummer entfernt.Sie können dies hier in Aktion sehen:
Update: Wenn Ihre tatsächliche Situation komplexer ist, müssen die REs natürlich geändert werden. Zum Beispiel, wenn Sie am Anfang und am Ende immer eine einzelne Zahl innerhalb von null oder mehr Nicht-Zahlen vergraben hatten:
quelle
Der Fall des OP gibt nicht an, dass es mehrere Übereinstimmungen in einer einzelnen Zeile geben kann, aber für den Google-Verkehr werde ich auch ein Beispiel dafür hinzufügen.
Da das OP eine Gruppe aus einem Muster extrahieren muss, sind für die Verwendung
grep -o
2 Durchgänge erforderlich. Aber ich finde das immer noch die intuitivste Art, die Arbeit zu erledigen.Da die Prozessorzeit im Grunde genommen kostenlos ist, die Lesbarkeit für den Menschen jedoch von unschätzbarem Wert ist, neige ich dazu, meinen Code basierend auf der Frage zu überarbeiten: "In einem Jahr, was werde ich davon halten?" Für Code, den ich öffentlich oder mit meinem Team teilen möchte, werde ich sogar offen sein,
man grep
um herauszufinden, welche langen Optionen es gibt, und diese ersetzen. Wie so:grep --only-matching --extended-regexp
quelle
Sie können es mit der Shell tun
quelle
Für awk. Ich würde das folgende Skript verwenden:
quelle
([0-9+])
, sondern die gesamte Zeile.quelle