
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, us
Lä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 „ clean
oder“ raw
enthalten.
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 _raw
oder _clean
danach 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 grep
mit PCRE-Unterstützung erstellt) ist der reguläre Ausdruck ein Perl-kompatibler. In diesen regulären Ausdrücken \K
setzt 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. -o
gibt grep
den ü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 pcregrep
können Sie es auch schreiben:
pcregrep -o1 '^[^_]*_(.*?)_(clean|raw)'
Mit -o1
wird der Teil gedruckt, der mit dem ersten übereinstimmt (...)
.
Antwort2
Hier ist der Weg im Awk-Stil
awk -F'_' '/clean|raw/{ print $2}'