Extrahieren Sie mit sed einen Teilstring, der beim ersten Vorkommen des Endes stoppt

Extrahieren Sie mit sed einen Teilstring, der beim ersten Vorkommen des Endes stoppt

Ich habe einen String, aus dem ich einen Teilstring extrahieren muss, aber das Ende meines regulären Ausdrucks wird wiederholt. Ich möchte, dass sed bei der ersten Instanz des Endes meines regulären Ausdrucks stoppt, ähnlich wie instr()-Funktionen in vielen Sprachen die erste Instanz zurückgeben. Beispiel:

echo "This is a test some stuff I want string junk string end" | sed -n 's/.*\(.te.*ng\).*/\1/p' 
returns: test some stuff I want string junk string
I want to return: test some stuff I want string

Antwort1

grepAnsatz (erfordertPCREUnterstützung):

s="This is a test some stuff I want string junk string end"
grep -Po 'te.*?ng' <<< $s

AlternativeperlAnsatz:

perl -ne 'print "$&\n" if /te.*?ng/' <<< $s

Die Ausgabe (für beide Ansätze):

test some stuff I want string

  • .*?- ?hier istnicht geizigModifikator, weist auf Übereinstimmung hin inminimalistische Mode

Antwort2

Gehen Sie dazu in zwei Schritten vor: Entfernen Sie zuerst das Präfix (falls das Abschlusszeichen im Präfix vorhanden war), und entfernen Sie dann alles nach dem Präfix. Verwenden Sie den TBefehl, um eine Zeile zu überspringen, wenn sie nicht übereinstimmt:

echo "This is a test some stuff I want string junk string end" |
sed -n 's/.*\(.te.*ng\)/\1/; T; s/\(ng\).*/\1/p'

Alternativ können Sie zunächst die nicht übereinstimmenden Zeilen löschen und dann den Ersatz in Ruhe durchführen.

echo "This is a test some stuff I want string junk string end" |
sed '/.*\(.te.*ng\)/!d; s/.*\(.te.*ng\)/\1/; s/\(ng\).*/\1/'

Alternativ führen Sie die Ersetzungen und den endgültigen Ausdruck nur auf übereinstimmenden Zeilen durch.

echo "This is a test some stuff I want string junk string end" |
sed '/.*\(.te.*ng\)/ { s/.*\(.te.*ng\)/\1/; s/\(ng\).*/\1/p; }'

Antwort3

Ich würde in Ihrem Fall vorschlagen, den Cut-Befehl zu verwenden

echo "I am a useful and I am a string. Did I mention that I'm a string?" | cut -d "string" -f1

Das würde den String in drei Teile schneiden (vor dem ersten, nach dem zweiten und zwischen dem 'String'). Mit -d"" können Sie auswählen, welches Muster Sie als Cutter verwenden möchten und mit -fNumber wählen Sie, welcher Teil genommen werden soll. Problem: Der 'String' wird entfernt. Lösung:

String=`echo "I am a useful and I am a string. Did I mention that I'm a string?" | cut -d "string" -f1`
String="$(String) string"
echo $String

Es fügt das entfernte Trennzeichen "string" am Ende der Variable $String hinzu, die mit der Ausgabe definiert wurde

Antwort4

# So führen Sie den Greedy-Match durch: "test .*? string" mit POSIX sed

sed -e '
   /test.*string/!d;      # non-interesting line
   /^test/s/string/&\
/;                        # append marker after the first substring "string"
   /\n/{P;d;}             # initial portion of pattern space is our result
   s/test/\
&/;D;                     # remove portion before the substring "test"
' yourfile

Ein andererPOSIX-lyDie Methode besteht darin, die Teilzeichenkette "string" einzeln vom Ende des Musterraums zu entfernen, bis nur noch eine übrig ist (nach der Teilzeichenkette "test"). Dann muss nur noch die Teilzeichenkette "test" in den Vordergrund gebracht werden:

sed -e '
   :loop
      s/\(test.*string\).*string.*/\1/
   tloop
   /^test/!s/test/\
&/;/\n/D
' yourfile

verwandte Informationen