Ich möchte verwenden sed
, um irgendetwas in einer Zeichenfolge zwischen dem ersten AB
und dem ersten Vorkommen von AC
(einschließlich) durch zu ersetzen XXX
.
Zum Beispiel habe ich diese Zeichenfolge (diese Zeichenfolge ist nur für einen Test):
ssABteAstACABnnACss
und ich möchte eine Ausgabe wie folgt aus : ssXXXABnnACss
.
Ich habe das gemacht mit perl
:
$ echo 'ssABteAstACABnnACss' | perl -pe 's/AB.*?AC/XXX/'
ssXXXABnnACss
aber ich möchte es mit implementieren sed
. Folgendes (unter Verwendung des Perl-kompatiblen regulären Ausdrucks) funktioniert nicht:
$ echo 'ssABteAstACABnnACss' | sed -re 's/AB.*?AC/XXX/'
ssXXXss
text-processing
sed
regular-expression
بارپابابا
quelle
quelle
Antworten:
Sed Regexes entsprechen der längsten Übereinstimmung. Sed hat kein Äquivalent zu nicht gierig.
Offensichtlich wollen wir Match machen
AB
,Gefolgt von
AC
,gefolgt von
AC
Leider
sed
kann # 2 nicht ausgeführt werden - zumindest nicht für einen regulären Ausdruck mit mehreren Zeichen. Natürlich können wir für einen einzelnen regulären Ausdruck wie@
(oder sogar[123]
)[^@]*
oder tun[^123]*
. Und so können wir die Einschränkungen von sed umgehen, indem wir alle Vorkommen vonAC
to ändern@
und danach suchenAB
,Gefolgt von
@
,gefolgt von
@
so was:
Der letzte Teil ändert nicht übereinstimmende Instanzen von
@
back zuAC
.Dies ist natürlich ein rücksichtsloser Ansatz, da die Eingabe bereits
@
Zeichen enthalten kann. Wenn Sie also übereinstimmen, erhalten Sie möglicherweise falsch positive Ergebnisse. Da jedoch keine Shell-Variable jemals ein NUL (\x00
) -Zeichen enthalten wird, ist NUL wahrscheinlich ein gutes Zeichen für die oben beschriebene Problemumgehung anstelle von@
:Die Verwendung von NUL erfordert GNU sed. (Um sicherzustellen, dass GNU-Funktionen aktiviert sind, darf der Benutzer die Shell-Variable POSIXLY_CORRECT nicht gesetzt haben.)
Wenn Sie sed mit dem GNU-
-z
Flag verwenden, um durch NUL getrennte Eingaben wie die Ausgabe von zu verarbeitenfind ... -print0
, befindet sich NUL nicht im Musterbereich, und NUL ist hier eine gute Wahl für die Substitution.Obwohl NUL nicht in einer Bash-Variablen enthalten sein kann, ist es möglich, es in einen
printf
Befehl aufzunehmen. Wenn Ihre Eingabezeichenfolge überhaupt ein Zeichen enthalten kann, einschließlich NUL, lesen Sie die Antwort von Stéphane Chazelas, die eine clevere Escape-Methode hinzufügt.quelle
echo
oderprintf
ein `\ 000 'ganz gut in Bash (oder die Eingabe könnte aus einer Datei stammen). Aber im Allgemeinen ist es natürlich nicht wahrscheinlich, dass eine Textfolge NULs enthält.AC
zuAC@
und zurück wechseln würden?Einige
sed
Implementierungen unterstützen dies.ssed
hat einen PCRE-Modus:AT & T ast sed hat Konjunktion und Negation, wenn erweiterte reguläre Ausdrücke verwendet werden :
Portabel können Sie diese Technik anwenden: Ersetzen Sie die Endzeichenfolge (hier
AC
) durch ein einzelnes Zeichen, das weder in der Anfangs- noch in der Endzeichenfolge (wie:
hier) vorkommts/AB[^:]*://
, und falls dieses Zeichen in der Eingabe vorkommt Verwenden Sie einen Escape-Mechanismus, der nicht mit den Anfangs- und Endzeichenfolgen kollidiert.Ein Beispiel:
Bei GNU
sed
besteht ein Ansatz darin, Newline als Ersatzzeichen zu verwenden. Dased
eine Zeile nach der anderen verarbeitet wird, wird im Musterbereich niemals eine neue Zeile eingefügt, sodass Folgendes möglich ist:Bei anderen
sed
Implementierungen funktioniert das im Allgemeinen nicht , da sie nicht unterstützt werden[^\n]
. Bei GNU müssensed
Sie sicherstellen, dass die POSIX-Kompatibilität nicht aktiviert ist (wie bei der Umgebungsvariablen POSIXLY_CORRECT).quelle
Nein, sed reguläre Ausdrücke haben keine nicht gierigen Übereinstimmungen.
Sie können den gesamten Text bis zum ersten Auftreten von
AC
abgleichen, indem Sie "alles , was nichts enthältAC
" gefolgt von verwendenAC
. Dies entspricht dem von Perl.*?AC
. Die Sache ist, dass „alles, was nichts enthältAC
“ nicht einfach als regulärer Ausdruck ausgedrückt werden kann: Es gibt immer einen regulären Ausdruck, der die Negation eines regulären Ausdrucks erkennt, aber der Negations-Regex wird schnell kompliziert. Und in portablem sed ist dies überhaupt nicht möglich, da der Negations-Regex die Gruppierung einer Alternative erfordert, die in erweiterten regulären Ausdrücken (z. B. in awk), aber nicht in portablen regulären Grundausdrücken vorhanden ist. Einige Versionen von sed, wie GNU sed, haben Erweiterungen für BRE, mit denen alle möglichen regulären Ausdrücke ausgedrückt werden können.Aufgrund der Schwierigkeit, einen regulären Ausdruck zu negieren, lässt sich dies nicht gut verallgemeinern. Stattdessen können Sie die Linie vorübergehend transformieren. In einigen sed-Implementierungen können Sie Zeilenumbrüche als Marker verwenden, da diese nicht in einer Eingabezeile angezeigt werden können (und wenn Sie mehrere Marker benötigen, verwenden Sie Zeilenumbrüche gefolgt von einem unterschiedlichen Zeichen).
Beachten Sie jedoch, dass Backslash-Newline in einigen sed-Versionen in einem Zeichensatz nicht funktioniert. Dies funktioniert insbesondere nicht in GNU sed, der sed-Implementierung unter nicht eingebettetem Linux. in GNU sed können Sie
\n
stattdessen verwenden:In diesem speziellen Fall reicht es aus, die erste
AC
Zeile durch eine neue zu ersetzen . Der Ansatz, den ich oben vorgestellt habe, ist allgemeiner.Ein leistungsfähigerer Ansatz in sed besteht darin, die Linie im Haltebereich zu speichern, alle bis auf den ersten „interessanten“ Teil der Linie zu entfernen, den Haltebereich und den Musterbereich auszutauschen oder den Musterbereich an den Haltebereich anzuhängen und zu wiederholen. Wenn Sie jedoch anfangen, so komplizierte Dinge zu tun, sollten Sie sich wirklich überlegen, auf awk umzusteigen. Awk hat auch keine nicht gierigen Übereinstimmungen, aber Sie können eine Zeichenfolge teilen und die Teile in Variablen speichern.
quelle
s/\n//g
Entfernt alle Zeilenumbrüche.sed - nicht gieriges Matching von Christoph Sieghart
quelle
In Ihrem Fall können Sie das schließende Zeichen einfach auf folgende Weise negieren:
quelle
AB
und dem ersten Auftreten vonAC
durchXXX
... ersetzen " und gibtssABteAstACABnnACss
als Beispiel eine Eingabe. Diese Antwort funktioniert für dieses Beispiel , beantwortet aber die Frage im Allgemeinen nicht. Zum BeispielssABteCstACABnnACss
sollte auch die Ausgabe ergebenaaXXXABnnACss
, aber Ihr Befehl durchläuft diese Zeile unverändert.