Wie extrahiert man Zeilen, wenn eine der beiden Übereinstimmungszeichenfolgen übereinstimmt?

Wie extrahiert man Zeilen, wenn eine der beiden Übereinstimmungszeichenfolgen übereinstimmt?

Ich habe eine Datei mit einigen Informationszeilen, die den Ländernamen enthalten, wie unten gezeigt.

$cat country.txt

max_china_clean_foo
man_india_raw_bar
max_us_clean_bax
max_uk_raw_bar
max_canada_raw_foo
max_au_clean_bar

Ich möchte nur die Ländernamen aus dieser Datei extrahieren. Ich verwende derzeit den folgenden Code, um den Ländernamen in einer For-Schleife zu extrahieren

val=${val#*_}
val=${val%_clean*}
echo $val

Die Ausgabe enthält jedoch nur china, usLändernamen au, sodass ich den gleichen Code mit geringfügigen Änderungen wiederholen muss, um die verbleibenden Länder wie unten zu extrahieren

val=${val#*_}
val=${val%_raw*}
echo $val

Ich weiß, dass dies keine eindeutige Art der Kodierung ist, und brauche daher Ihre Hilfe beim Extrahieren der Ländernamen aus allen Zeilen, die entweder die Zeichenfolge „ cleanoder“ rawenthalten.

Gibt es eine Möglichkeit, mit awk oder sed alle Ländernamen mit zwei Match-Schlüsseln zu extrahieren? Meine Ausgabe sollte so aussehen

china
india
us
uk
canada
au

Antwort1

Ich würde keine Shell-Schleife zur Textverarbeitung verwenden.

Hier können Sie einfach Folgendes tun:

cut -d _ -f 2 < country.txt

_Oder wenn die Eingabe Zeilen ohne Zeichen enthalten kann :

awk -F _ 'NF >= 2 {print $2}' < country.txt

Wenn der Ländername _Zeichen enthalten kann und Sie stattdessen den Teil der Zeile zwischen dem ersten _und dem ersten Vorkommen _rawoder _cleandanach zurückgeben möchten, können Sie Folgendes tun:

perl -ne 'print $1 if s/^[^_]*_(.*?)_(clean|raw)/' < country.txt

Oder mit GNU grep:

grep -Po '^[^_]*_\K.*?(?=_clean|_raw)' < country.txt

Bei -P(sofern grepmit PCRE-Unterstützung erstellt) ist der reguläre Ausdruck ein Perl-kompatibler. In diesen regulären Ausdrücken \Ksetzt es den Anfang der übereinstimmenden Zeichenfolge zurück und (?=...)ist ein Vorausschauoperator, d. h. es wird geprüft, ob der Rest der Zeichenfolge übereinstimmt, ...ohne dass dieser Teil im übereinstimmenden Teil enthalten ist. -ogibt grepden übereinstimmenden Teil aus, also wird hier gedruckt, was mit dem .*?obigen übereinstimmt, was das nicht gierige Äquivalent von ist .*, d. h. eine Folge von 0 oder mehr Zeichen, so kurz wie möglich, in diesem Fall nach einer Folge von 0 oder mehr Unterstrichen ( [^_]*), die am Anfang der Zeile gefunden wurden ( ), gefolgt von einem Unterstrich und vorausgesetzt, dass darauf entweder oder ^folgt ._raw_clean

Mit pcregrepkönnen Sie es auch schreiben:

pcregrep -o1 '^[^_]*_(.*?)_(clean|raw)'

Mit -o1wird der Teil gedruckt, der mit dem ersten übereinstimmt (...).

Antwort2

Hier ist der Weg im Awk-Stil

awk -F'_' '/clean|raw/{ print $2}'

verwandte Informationen