it-swarm.com.de

Wie verwendet man sed, awk oder gawk, um nur das zu drucken, was übereinstimmt?

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. Nehmen wir ein Beispiel:

Beispiel regulärer Ausdruck:

.*abc([0-9]+)xyz.*

Beispiel 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 mir erhofft hatte, ist aus meinem Bash-Skript heraus:

myvalue=$( sed <...something...> input.txt )

Dinge, die ich ausprobiert 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
95
Stéphane

Mein sed (Mac OS X) funktionierte nicht mit +. Ich habe es versucht * stattdessen und ich fügte p Tag zum Drucken von Übereinstimmungen hinzu:

sed -n 's/^.*abc\([0-9]*\)xyz.*$/\1/p' example.txt

Zum Abgleichen von mindestens einem numerischen Zeichen ohne +, Ich würde ... benutzen:

sed -n 's/^.*abc\([0-9][0-9]*\)xyz.*$/\1/p' example.txt
43
mouviciel

Sie können sed verwenden, um dies zu tun

 sed -rn 's/.*abc([0-9]+)xyz.*/\1/gp'
  • -n Druckt die resultierende Zeile nicht aus
  • -r Dies macht es so, dass Sie nicht die Erfassungsgruppe parens () Entkommen können.
  • \1 Die Übereinstimmung der Erfassungsgruppe
  • /g Globale Übereinstimmung
  • /p Gibt das Ergebnis aus

Ich habe ein Tool für mich geschrieben, das das einfacher macht

rip 'abc(\d+)xyz' '$1'
32
Ilia Choly

Ich benutze Perl, um mir das zu erleichtern. z.B.

Perl -ne 'print $1 if /.*abc([0-9]+)xyz.*/'

Dadurch wird Perl ausgeführt. Die Option -n Weist Perl an, jeweils eine Zeile aus STDIN einzulesen und den Code auszuführen. Die Option -e Gibt die auszuführende Anweisung an.

Der Befehl führt einen regulären Ausdruck für die gelesene Zeile aus und gibt bei Übereinstimmung den Inhalt des ersten Satzes von Klammern aus ($1).

Sie können dazu auch mehrere Dateinamen am Ende verwenden. z.B.

Perl -ne 'print $1 if /.*abc([0-9]+)xyz.*/' example1.txt example2.txt

17
PP.

Wenn Ihre Version von grep dies unterstützt, können Sie das -o Option zum Ausdrucken nur der Teil einer Zeile, der Ihrem regulären Ausdruck entspricht.

Wenn nicht, dann ist hier das beste sed, das ich mir einfallen lassen könnte:

sed -e '/[0-9]/!d' -e 's/^[^0-9]*//' -e 's/[^0-9]*$//'

... löscht/überspringt ziffernlos und entfernt in den verbleibenden Zeilen alle führenden und nachfolgenden nicht-ziffernförmigen Zeichen. (Ich vermute nur, dass Sie beabsichtigen, die Nummer aus jeder Zeile zu extrahieren, die eine enthält).

Das Problem mit so etwas wie:

sed -e 's/.*\([0-9]*\).*/&/' 

.... oder

sed -e 's/.*\([0-9]*\).*/\1/'

... ist, dass sed nur "gierige" Übereinstimmungen unterstützt ... also stimmt das erste. * mit dem Rest der Zeile überein. Solange wir keine negierte Zeichenklasse verwenden können, um eine nicht gierige Übereinstimmung zu erzielen ... oder eine Version von sed mit Perl-kompatiblen oder anderen Erweiterungen der regulären Ausdrücke, können wir aus with keine präzise Musterübereinstimmung extrahieren der Musterraum (eine Linie).

5
Jim Dennis

Sie können awk mit match() verwenden, um auf die erfasste Gruppe zuzugreifen:

$ awk 'match($0, /abc([0-9]+)xyz/, matches) {print matches[1]}' file
12345

Dies versucht, das Muster abc[0-9]+xyz Abzugleichen. In diesem Fall werden die Slices im Array matches gespeichert, dessen erstes Element der Block [0-9]+ Ist. Da match() die Zeichenposition oder den Index zurückgibt, an der dieser Teilstring beginnt (1, wenn er am Anfang des Strings beginnt) , löst es die Aktion print aus.


Mit grep können Sie einen Blick hinter die Kulissen und einen Blick nach vorn verwenden:

$ grep -oP '(?<=abc)[0-9]+(?=xyz)' file
12345

$ grep -oP 'abc\K[0-9]+(?=xyz)' file
12345

Dies überprüft das Muster [0-9]+, Wenn es innerhalb von abc und xyz auftritt, und gibt nur die Ziffern aus.

3
fedorqui

Perl ist die sauberste Syntax, aber wenn Sie nicht über Perl verfügen (ich verstehe, dass dies nicht immer der Fall ist), können Sie gawk und Komponenten eines regulären Ausdrucks nur mit der Funktion gensub verwenden.

gawk '/abc[0-9]+xyz/ { print gensub(/.*([0-9]+).*/,"\\1","g"); }' < file

die Ausgabe der Beispieleingabedatei erfolgt

12345

Hinweis: gensub ersetzt den gesamten regulären Ausdruck (zwischen dem //), daher müssen Sie das. * Vor und nach dem ([0-9] +) einfügen, um den Text vor und nach der Zahl in der Ersetzung zu entfernen.

2
Mark Lakata

Wenn Sie Linien auswählen möchten, streifen Sie die nicht gewünschten Bits aus:

egrep 'abc[0-9]+xyz' inputFile | sed -e 's/^.*abc//' -e 's/xyz.*$//'

Grundsätzlich werden die gewünschten Zeilen mit egrep ausgewählt und anschließend mit sed die Bits vor und nach der Zahl entfernt.

Sie können dies hier in Aktion sehen:

pax> echo 'a
b
c
abc12345xyz
a
b
c' | egrep 'abc[0-9]+xyz' | sed -e 's/^.*abc//' -e 's/xyz.*$//'
12345
pax> 

pdate: Wenn deine aktuelle Situation komplexer ist, müssen die REs mir natürlich modifiziert werden. Wenn Sie zum Beispiel immer eine einzelne Zahl innerhalb von null oder mehr nicht numerischen Zeichen am Anfang und am Ende vergraben haben:

egrep '[^0-9]*[0-9]+[^0-9]*$' inputFile | sed -e 's/^[^0-9]*//' -e 's/[^0-9]*$//'
1
paxdiablo