sed: Text zwischen einer Zeichenfolge löschen, bis zum ersten Vorkommen einer anderen Zeichenfolge

sed: Text zwischen einer Zeichenfolge löschen, bis zum ersten Vorkommen einer anderen Zeichenfolge

Stellen Sie sich vor, ich habe etwa den folgenden Text:

Der schnelle braune Fuchs springt 2012 und 2013

Und ich möchte den Teil von „fox“ einschließlich der vier Zahlen löschen, aber nur beim ersten Vorkommen, sodass ich am Ende Folgendes habe:

Die schnelle braune und 2013

So etwas in der Art...:

echo "Der schnelle braune Fuchs springt 2012 und 2013" \
   | sed "s/fox.*\([0-9]\{4\}\)//g"

...bringt mich:

Das schnelle Braun

Daher wurde alles entfernt, einschließlich des letzten Vorkommens der vier Zahlen.

Irgendwelche Ideen?

Antwort1

Von verwendete POSIX-reguläre Ausdrücke sed(sowohl die „Basis“- als auch die „erweiterte“ Version) unterstützen keine nicht gierigen Übereinstimmungen. (Obwohl es einige Workarounds gibt, wie z. B. die Verwendung [^0-9]*von anstelle von .*, werden diese unzuverlässig, wenn die Eingaben stark variieren.)

?Was Sie brauchen, lässt sich in Perl durch die Verwendung des nicht gierigen Quantifizierers erreichen :

echo "The quick brown fox jumps in 2012 and 2013" \
   | perl -pe 's/fox.*?([0-9]{4})//g'

Möglicherweise möchten Sie auch ein zusätzliches Leerzeichen entfernen.

Antwort2

Angenommen, Sie möchtennursed und Sie möchten, dass das Ende der Übereinstimmung die erste Zifferngruppe ist, ohne sich darum zu kümmern, welches Wort nach den Ziffern kommt, dann funktioniert das:

echo "Der schnelle braune Fuchs springt 2012 und 2013" \
   | sed "s/fox[^0-9][^0-9]*[0-9][0-9]* //"

Das Muster funktioniert, indem es fox, gefolgt von einer oder mehreren Nicht-Ziffern [^0-9][^0-9]*, gefolgt von 1 oder mehreren Ziffern abgleicht [0-9][0-9]*. Dieses Muster funktioniert mit einer beliebigen Anzahl von Ziffern, nicht nur mit 4. Wenn Sie genau 4 Ziffern abgleichen möchten, ändern Sie es in:

echo "Der schnelle braune Fuchs springt 2012 und 2013" \
   | sed "s/fox[^0-9]*\([0-9]\{4\}\) //"

Antwort3

Sie haben nicht angegebengenauwas Ihre Anforderungen sind. Möglicherweise möchten Sie einen mehrstufigen Prozess. Wählen Sie eine Zeichenfolge, von der Sie wissen, dass sie in Ihrer Eingabe nicht vorkommt (z. B. ####):

echo "Der schnelle braune Fuchs überspringt 2012 und 2013 42 faule Hunde." \
  | sed \
        -e "s/[0-9]\{4\}/&####/" \
        -e "s/fox.*####//" \
        -e "s/####//"

(Befehl zur besseren Lesbarkeit übermäßig gefaltet.) Die -e "s/[0-9]\{4\}/&####/"Injektionen ####nachder erstevierstellige Zahl. (Achtung: Dies ändert sich 65536in 6553####6.)
-e "s/fox.*####//"betrifft Zeilen, die foxund enthalten ####- also Zeilen, die mindestens eine vierstellige Zahl enthalten - und löscht dann von foxbisder erstevierstellige Zahl.
-e "s/####//"löscht natürlich alle ####Zeichenfolgen, die von Zeilen übrig bleiben, die eine vierstellige Zahl enthalten, aber nicht fox.

Um auch ein Leerzeichen nach der Nummer zu entfernen, falls eines vorhanden ist,

echo "Der schnelle braune Fuchs überspringt 2012 und 2013 42 faule Hunde." \
  | sed \
        -e "s/[0-9]\{4\}/&####/" \
        -e "s/fox.*#### //" \
        -e "s/fox.*####//" \
        -e "s/####//"

Achtung: Sie können gzu allen sBefehlen etwas hinzufügen, aber da dieser immer noch verwendet .*, was die Ursache Ihres Problems ist, wird er trotzdem nicht funktionieren.

One fox jumps in 2012 and 2013, another fox will jump in 2014 and 2015.

wie Sie es wahrscheinlich wollen. Und natürlich Sienichtghinzufügen möchten "s/[0-9]\{4\}/&####/", weil dann wird es injizieren ####nachjedenvierstellige Zahl, was den ganzen Sinn zunichte macht. Dann "s/fox.*####//"wird es sich genauso verhalten wie "s/fox.*[0-9]\{4\}//"(Ihr ursprünglicher Befehl, bei dem die nicht beitragenden Zeichen entfernt wurden); das heißt, es wird sich ändern

Der schnelle braune Fuchs springt 2012 und 2013.

Zu

Der schnelle braune Fuchs springt in den Jahren 2012#### und 2013####.

und dann zu

Das schnelle Braun.

verwandte Informationen