Mir ist aufgefallen, dass wenn ich \n
ein Muster zum Ersetzen mit hinzufüge sed
, es nicht übereinstimmt. Beispiel:
$ cat > alpha.txt
This is
a test
Please do not
be alarmed
$ sed -i'.original' 's/a test\nPlease do not/not a test\nBe/' alpha.txt
$ diff alpha.txt{,.original}
$ # No differences printed out
Wie kann ich das zum Laufen bringen?
sed
regular-expression
utilities
Belmin Fernandez
quelle
quelle
Antworten:
Im einfachsten Aufruf von sed enthält es eine Textzeile im Musterbereich, d. H. 1 Zeile
\n
begrenzter Text aus der Eingabe. Die einzelne Zeile im Musterbereich hat keine\n
... Deshalb findet Ihr Regex nichts.Sie können mehrere Zeilen in den Musterraum einlesen und die Dinge überraschend gut, aber mit mehr als normalem Aufwand manipulieren. Sed verfügt über eine Reihe von Befehlen, die diese Art von Dingen ermöglichen ... Hier ist ein Link zu einer Befehlsübersicht für sed . Es ist das beste, das ich gefunden habe und das mich ins Rollen gebracht hat.
Vergessen Sie jedoch die "Einzeiler" -Idee, sobald Sie mit der Verwendung der Mikrobefehle von sed beginnen. Es ist nützlich, es wie ein strukturiertes Programm anzuordnen, bis Sie das Gefühl dafür bekommen ... Es ist überraschend einfach und ebenso ungewöhnlich. Sie können es sich als die "Assemblersprache" der Textbearbeitung vorstellen.
Zusammenfassung: Verwenden Sie sed für einfache Dinge, und vielleicht auch für etwas mehr, aber im Allgemeinen bevorzugen die meisten Leute etwas anderes, wenn es über das Arbeiten mit einer einzelnen Zeile hinausgeht ...
Ich lasse jemanden etwas anderes vorschlagen Ich bin mir nicht sicher, was die beste Wahl sein würde. (Ich würde sed verwenden, aber das liegt daran, dass ich Perl nicht gut genug kenne.)
Hier ist es das gleiche Skript, kondensierte in dem, was ist offensichtlich schwerer zu lesen und die Arbeit mit, aber einige würden unschlüssig nennen einen Einzeiler
Hier ist mein Befehl "Spickzettel"
quelle
t
Befehl hier zu verwenden - wenn Sie keine Beschriftung erhalten, verzweigt er standardmäßig zum Ende des Skripts. Tutsed '/^a test$/{$!{N;s/^a test\nPlease do not$/not a test\nBe/;t;P;D}}' alpha.txt
also unter allen Umständen genau das Gleiche wie Ihr Befehl. Das gleiche gilt natürlich auch für diese bestimmte Datei,sed '/test/{N;s/.*/not a test\nBe/}' alpha.txt
aber mein erstes Beispiel ist für alle möglichen Dateien logisch äquivalent . Beachten Sie auch, dass\n
in einer Ersatzzeichenfolge kein Zeilenumbruch erzeugt wird. Dazu benötigen Sie einen Backslash "\" gefolgt von einem tatsächlichen Zeilenumbruch.#
Befehl nicht von der vorherigen getrennt,\n
in RHS vons
). Mit GNU könnensed
Sie auch-z
NUL-getrennte Datensätze verwenden (und dann die gesamte Eingabe schlürfen, wenn es sich um Text handelt (der per Definition keine NULs enthält)).Verwenden Sie
perl
anstelle vonsed
:-pi -e
ist Ihre Standardbefehlszeilenfolge "Replace In Place", und -0777 bewirkt, dass Perl Dateien als Ganzes schlürft. Weitere Informationen finden Sie unter perldoc perlrun .quelle
sed
mit awk oder perl angefragt und geantwortet wird. Ich denke, es ist kein Thema, daher tut es mir leid, aber ich habe einen Minuspunkt abgegeben.sed
Antwort oben beweist, dass eine Perl-Antwort zum Thema gehört.Ich denke, es ist besser, das
\n
Symbol durch ein anderes Symbol zu ersetzen und dann wie gewohnt zu arbeiten:zB nicht bearbeiteter Quellcode:
kann geändert werden in:
Wenn jemand es nicht weiß,
\n
endet die UNIX-Linie,\r\n
- Windows,\r
- klassisches Mac OS. Normaler UNIX-Text verwendet kein\r
Symbol, daher ist es sicher, es für diesen Fall zu verwenden.Sie können auch ein exotisches Symbol verwenden, um \ n vorübergehend zu ersetzen. Als Beispiel - \ f (Formularvorschubsymbol). Weitere Symbole finden Sie hier .
quelle
\r
im Argument bissed
durch ersetzt werden$(printf '\r')
.$
vor dem sed-String einfügen, um zu verhindern, dass der\r
in einen konvertiert wirdr
. Kurzes Beispiel:sed $'s/\r/~/'
. Vollständiges Beispiel:cat alpha.txt | tr '\n' '\r' | sed $'s/a test\rPlease do not/not a test\rBe/' | tr '\r' '\n'
Alles in allem kann das Verschlingen der gesamten Datei der schnellste Weg sein.
Die grundlegende Syntax lautet wie folgt:
Wohlgemerkt, das Verschlingen der gesamten Datei ist möglicherweise keine Option, wenn die Datei enorm groß ist. In solchen Fällen bieten andere hier bereitgestellte Antworten maßgeschneiderte Lösungen, die garantiert einen geringen Speicherbedarf aufweisen.
In allen anderen Hack- und Slash-Situationen erledigt man den Job , wenn man nur das Präfix
-e '1h;2,$H;$!d;g'
gefolgt von dem ursprünglichensed
Regex-Argument verwendet.z.B
Was macht
-e '1h;2,$H;$!d;g'
das?Die
1
,2,$
,$!
Teile sind Linie , die Grenzlinien - Spezifizierer , die direkt folgenden Befehl läuft auf.1
: Nur erste Zeile2,$
: Alle Zeilen ab der Sekunde$!
: Jede andere Zeile als die letzteSo erweitert geschieht dies auf jeder Zeile eines N-Zeilen-Eingangs.
Der
g
Befehl erhält keinen Zeilenspezifizierer, aber der vorhergehended
Befehl enthält eine spezielle Klausel " Start next cycle. ", Die verhindert, dassg
alle Zeilen außer der letzten ausgeführt werden.Zur Bedeutung der einzelnen Befehle:
h
gefolgt vonH
s in jeder Zeile kopiert die Eingabezeilen insed
den Hold-Bereich . (Denken Sie an einen beliebigen Textpuffer.)d
verwirft jede Zeile von verhindert diese Zeilen an den Ausgang geschrieben wird. Der Laderaum bleibt jedoch erhalten.g
die Akkumulation jeder Zeile aus dem Haltebereich wiederhergestellt , sodasssed
der reguläre Ausdruck für die gesamte Eingabe (und nicht zeilenweise) ausgeführt werden kann Spiel auf\n
s.quelle
sed
hat drei Befehle mehrzeiligen Operationen zu verwalten:N
,D
undP
(vergleichen sie mit normalenn
,d
undp
).In diesem Fall können Sie die erste Zeile Ihres Musters
N
abgleichen, die zweite Zeile an den Musterbereich anhängen und danns
Ihre Ersetzung vornehmen.So etwas wie:
quelle
G
,H
,x
...). Mit dems
Befehl können auch weitere Zeilen in den Musterbereich eingefügt werden .N
BefehleSie können, aber es ist schwierig . Ich empfehle, zu einem anderen Werkzeug zu wechseln. Wenn es einen regulären Ausdruck gibt, der niemals mit einem Teil des zu ersetzenden Textes übereinstimmt, können Sie ihn in GNU awk als Trennzeichen für awk-Datensätze verwenden.
Wenn Ihre Suchzeichenfolge nie zwei aufeinanderfolgende Zeilenumbrüche enthält, können Sie den "Absatzmodus" von awk verwenden (eine oder mehrere Leerzeilen trennen Datensätze).
Eine einfache Lösung besteht darin, Perl zu verwenden und die Datei vollständig in den Speicher zu laden.
quelle
perl -0777 -pe '…' <input-file >output-file
. So ändern Sie eine Datei an Ort und Stelle:perl -0777 -i -pe '…' filename
sed
‚s --z
Option (hinzugefügt im Jahr 2012 nach , dass Antwort geschrieben wurde):seq 10 | sed -z 's/4\n5/a\nb/'
.Ich denke, das ist die sed-Lösung für 2 passende Zeilen.
Wenn Sie 3 passende Zeilen haben wollen, dann ...
Wenn Sie 4 übereinstimmende Zeilen möchten, dann ...
Wenn das Ersatzteil in den "s" -Befehlszeilen schrumpft, dann ist das etwas komplizierter
Wenn der Repacement-Teil Linien wachsen lässt, ist dies etwas komplizierter
quelle
Hier
/a test/,/Please do not/
wird als Textblock (mehrzeilig)c
der Änderungsbefehl gefolgt von neuem Text betrachtetnot a test \nBe
Für den Fall, dass der zu ersetzende Text sehr lang ist, würde ich ex- Syntax vorschlagen .
quelle
Erweitern Sie einfach Ihr Fenster bei der Eingabe ein wenig.
Das ist ziemlich einfach. Neben der Standardsubstitution; Sie brauchen nur
$!N
,P
undD
hier.quelle
Abgesehen von Perl ist ein allgemeiner und praktischer Ansatz für die mehrzeilige Bearbeitung von Streams (und auch Dateien):
Erstellen Sie zuerst einen neuen UNIQUE-Zeilentrenner, wie Sie möchten
Dann ersetzen Sie in Ihrem sed-Befehl (oder einem anderen Tool) \ n durch $ {S} wie
(awk ersetzt ASCII-Zeilentrennzeichen durch deins und umgekehrt.)
quelle
Dies ist eine kleine Modifikation der cleveren Antwort von xara, damit sie unter OS X funktioniert (ich verwende 10.10):
Anstatt explizit zu verwenden
\r
, müssen Sie verwenden$(printf '\r')
.quelle
printf '\r'
(oderecho -e '\r'
) ordnungsgemäß funktionieren$'\r'
. Beispiel:echo hi$'\n'there
Gibt eine neue Zeile zwischenhi
und austhere
. In ähnlicher Weise können Sie die gesamte Zeichenfolge\
echo $'hi\nthere'
Ich wollte einer Datei mit sed ein paar Zeilen HTML hinzufügen (und landete hier). Normalerweise würde ich nur Perl verwenden, aber ich war auf einer Box, die sed, bash und sonst nicht viel hatte. Ich fand heraus, dass, wenn ich den String in eine einzelne Zeile änderte und bash / sed das \ t \ n interpolieren ließ, alles klappte:
Es wäre sauberer, eine Funktion zu haben, die den doppelten Anführungszeichen und Schrägstrichen entgeht, aber manchmal ist die Abstraktion der Dieb der Zeit.
quelle
GNU
sed
hat eine-z
Option, die es erlaubt, die Syntax zu verwenden, die das OP anzuwenden versucht hat. ( Manpage )Beispiel:
Beachten Sie: Wenn Sie
^
und verwenden$
, stimmen sie jetzt mit dem Anfang und dem Ende von Zeilen überein, die mit einem NUL-Zeichen (nicht\n
) getrennt sind.\n
Vergessen Sie nicht, dasg
Flag für globale Ersetzungen (zs/.../.../g
. B. ) zu verwenden , um sicherzustellen, dass Übereinstimmungen in allen (durch Trennzeichen getrennten) Zeilen ersetzt werden .Credits: @ stéphane-chazelas zuerst erwähnt -z in einem Kommentar oben.
quelle
Sed unterbricht die Eingabe in Zeilenumbrüchen. Es bleibt nur eine Zeile pro Schleife.
Daher gibt es keine Möglichkeit, eine
\n
(Newline) zuzuordnen, wenn der Musterbereich sie nicht enthält.Es gibt jedoch eine Möglichkeit, mit der Schleife zwei aufeinanderfolgende Zeilen im Musterbereich zu halten :
Fügen Sie die erforderliche Verarbeitung zwischen dem N und dem P hinzu (ersetzen Sie das
l
).In diesem Fall (2 Zeilen):
Oder für drei Zeilen:
Dies setzt voraus, dass die gleiche Anzahl von Zeilen ersetzt wird.
quelle