Mit der bash
Shell in einer Datei mit Zeilen wie den folgenden
first "line"
<second>line and so on
Ich möchte ein oder mehr Vorkommen von ersetzen "line"\n<second>
mit other characters
und jedes Mal zu erhalten:
first other characters line and so on
Daher muss ich eine Zeichenfolge sowohl durch Sonderzeichen wie "
und <
als auch durch ein Zeilenumbruchzeichen ersetzen.
Nachdem ich zwischen den anderen Antworten gesucht hatte, stellte ich fest, dass sed
Zeilenumbrüche auf der rechten Seite des Befehls (also der other characters
Zeichenfolge) akzeptiert werden können, nicht jedoch auf der linken Seite.
Gibt es eine Möglichkeit (einfacher als diese ), dieses Ergebnis mit sed
oder zu erhalten grep
?
text-processing
sed
grep
newlines
BowPark
quelle
quelle
\n
ewline Aussage, die Sie machen, ist, warum ich frage. Leute fragen selten, ob sies//\n/
mit GNU so gut wie möglich machen könnensed
, obwohl die meisten anderensed
diese Flucht auf der rechten Seite ablehnen. Trotzdem\n
funktioniert die Escape-Funktion in jedem POSIX linkssed
und Sie können sie portabel übersetzen,y/c/\n/
obwohl sie den gleichen Effekt hat wies/c/\n/g
und daher nicht immer so nützlich ist.Antworten:
Drei verschiedene
sed
Befehle:Sie alle drei bauen auf dem Grundbefehl
s///
ubstitution auf:Sie alle versuchen auch, beim Umgang mit der letzten Zeile
sed
vorsichtig zu sein , da sie sich in Randfällen in Bezug auf ihre Ausgabe unterscheiden. Dies ist die Bedeutung$!
einer Adresse, die mit jeder Zeile übereinstimmt, die!
nicht die$
letzte ist.Sie alle verwenden auch den
N
Befehl ext, um die nächste Eingabezeile nach einem\n
Ewline-Zeichen an den Musterbereich anzuhängen. Jeder, der schon längersed
dabei ist, wird gelernt haben, sich auf den\n
ewline-Charakter zu verlassen - denn der einzige Weg, einen zu bekommen, besteht darin, ihn explizit dort abzulegen.Alle drei versuchen, so wenig Eingaben wie möglich einzulesen, bevor sie Maßnahmen ergreifen. Sie handeln
sed
so schnell wie möglich und müssen vorher nicht die gesamte Eingabedatei einlesen.Obwohl sie alle tun
N
, unterscheiden sich alle drei in ihren Rekursionsmethoden.Erster Befehl
Der erste Befehl verwendet eine sehr einfache
N;P;D
Schleife. Diese drei Befehle sind in alle POSIX-kompatiblen Befehle integriertsed
und ergänzen sich hervorragend.N
- Wie bereits erwähnt, wird dieN
ext-Eingabezeile nach einem eingefügten\n
ewline-Trennzeichen an den Musterraum angehängt.P
- wiep
; EsP
druckt den Musterraum - aber nur bis zum ersten vorkommenden\n
Ewline-Zeichen. Und so unter Berücksichtigung der folgenden Eingabe / Befehl:printf %s\\n one two | sed '$!N;P;d'
sed
P
spült nur einen . Mit ...D
- wied
; esD
löst einen Musterraum aus und beginnt einen weiteren Linienzyklus. Im Gegensatz dazud
wirdD
nur bis zur ersten auftretenden\n
Ewline im Musterraum gelöscht. Wenn nach dem\n
ewline-Zeichen mehr Muster vorhanden ist ,sed
beginnt der nächste Zeilenzyklus mit dem verbleibenden. Wenn died
im vorherigen Beispiel durch a ersetzt würdenD
,sed
würden beispielsweiseP
sowohl eins als auch zwei gedruckt .Dieser Befehl wird nur für Zeilen wiederholt, die nicht mit der
s///
ubstitution-Anweisung übereinstimmen. Da dies///
Ubstitution die\n
hinzugefügte Ewline entferntN
, bleibt nie etwas übrig, wenn der Musterraum gelöscht wirdsed
D
.Es könnten Tests durchgeführt werden, um das
P
und / oderD
selektiv anzuwenden , aber es gibt andere Befehle, die besser zu dieser Strategie passen. Da die Rekursion implementiert ist, um aufeinanderfolgende Zeilen zu verarbeiten, die nur einem Teil der Ersetzungsregel entsprechen, funktionieren aufeinanderfolgende Zeilenfolgen, die mit beiden Enden ders///
Substitution übereinstimmen, nicht gut:Angesichts dieser Eingabe:
... es druckt ...
Es funktioniert jedoch
...Alles gut.
Zweiter Befehl
Dieser Befehl ist dem dritten sehr ähnlich. Beide verwenden ein
:b
Ranch /t
Est-Label (wie auch in der Antwort von Joeseph R. hier gezeigt wird ) und greifen unter bestimmten Bedingungen darauf zurück.-e :n -e
- Portablesed
Skripte begrenzen eine:
Label-Definition entweder mit einer\n
ewline oder einer neuen inline-e
xecution-Anweisung.:n
- definiert eine Bezeichnung mit dem Namenn
. Dies kann jederzeit mit entwederbn
oder zurückgegeben werdentn
.tn
- Dert
Befehl est kehrt zu einer angegebenen Bezeichnung zurück (oder beendet, falls keine angegeben ist, das Skript für den aktuellens///
Zeilenzyklus ), wenn eine Substitution vorliegt, da entweder die Bezeichnung definiert wurde oder sie zuletzt alst
ests erfolgreich bezeichnet wurde.In diesem Befehl erfolgt die Rekursion für die übereinstimmenden Zeilen. Wenn
sed
das Muster erfolgreich durch andere Zeichen ersetzt wurde ,sed
kehrt es zur:n
Beschriftung zurück und versucht es erneut. Wenn keines///
Substitution durchgeführt wird,sed
druckt der Musterraum automatisch und beginnt den nächsten Zeilenzyklus.Dies neigt dazu, aufeinanderfolgende Sequenzen besser zu handhaben. Wo der letzte fehlgeschlagen ist, wird Folgendes gedruckt:
Dritter Befehl
Wie bereits erwähnt, ist die Logik hier der letzten sehr ähnlich, aber der Test ist expliziter.
/"$/bn
- Das istsed
der Test. Da derb
Befehl ranch eine Funktion dieser Adresse ist,sed
wird erst nach dem Anhängen einer Ewline und dem Beenden des Musterbereichs mit einem doppelten Anführungszeichen eineb
Ranch wiederhergestellt .:n
\n
"
Zwischen
N
undb
wie möglich wird so wenig getan - auf diese Weisesed
können sehr schnell genau so viele Eingaben wie nötig gesammelt werden, um sicherzustellen, dass die folgende Zeile nicht mit Ihrer Regel übereinstimmt. Dies///
Substitution unterscheidet sich hier darin, dass sie dieg
Lobalflagge verwendet - und daher alle notwendigen Ersetzungen auf einmal vornimmt. Bei identischer Eingabe wird dieser Befehl identisch mit dem letzten ausgegeben.quelle
DATA
und wie erhalten Sie die Texteingabe?<<\DATA\ntext input\nDATA\n
ist eingebrannt, aber das ist nur Text,sed
den die Shell in einem Dokument hier übergeben hat . Es würde genauso gut funktionieren wiesed 'script' filename
oderprocess that writes to stdout | sed 'script'
. Hilft das?D
jede geänderte Zeile doppelt? (Sie haben es verwendet, wie es notwendig ist; vielleicht weiß ich es nichtsed
sehr gut)D
daD
sonstD
aus der Ausgabe das, was Sie jetzt sehen, verdoppelt wird. Ich habe gerade eine Bearbeitung vorgenommen - und ich kann das auch bald erweitern.D
Sache befasst.Nun, ich kann mir ein paar einfache Möglichkeiten vorstellen, aber keine beinhaltet
grep
(was sowieso keine Substitutionen macht) odersed
.Perl
Um jedes Vorkommen von
"line"\n<second>
durch zu ersetzenother characters
, verwenden Sie:Oder verwenden Sie Folgendes, um mehrere aufeinanderfolgende Vorkommen
"line"\n<second>
als eins zu behandeln und alle durch ein einziges zu ersetzenother characters
:Beispiel:
Das
-00
bewirkt , dass die Datei in Perl „paragraph Modus“ lesen was bedeutet , dass „Linien“ von definiert sind ,\n\n
statt\n
im Wesentlichen jeder Absatz als Linie behandelt wird. Die Ersetzung stimmt daher über eine neue Zeile überein.awk
Die gleiche Grundidee: Wir setzen das Datensatztrennzeichen (
RS
) so\n\n
, dass die gesamte Datei verschluckt wird, dann das Ausgabe-Datensatztrennzeichen auf nichts (andernfalls wird eine zusätzliche neue Zeile gedruckt) und verwenden dann diesub()
Funktion, um die Ersetzung vorzunehmen.quelle
awk
sollte seinprint;}' file
. Ich muss Perl meiden und vorzugsweise verwendensed
, trotzdem haben Sie gute Alternativen vorgeschlagen.Lesen Sie die gesamte Datei und ersetzen Sie sie global:
quelle
${cmds}
ist GNU-spezifisch - die meisten anderensed
erfordern eine\n
Ewline oder eine-e
Pause zwischenp
und}
. Sie können die Klammern insgesamt - und portabel - vermeiden und sogar vermeiden, ein zusätzliches\n
ewline-Zeichen in die erste Zeilesed 'H;1h;$!d;x;s/"line"\n<second>/other characters /g'
sed -n '1{h;n};H; ${x; s/"line"\n<second>/other characters /g; p}'
- Dies wird jedoch nicht mehr zu warten.Hier ist eine Variante von Glenns Antwort , die funktioniert, wenn Sie mehrere aufeinanderfolgende Vorkommen haben (funktioniert nur mit GNU
sed
):Das
:x
ist nur ein Etikett zum Verzweigen. Im Grunde bedeutet dies, dass die Zeile nach dem Ersetzen überprüft wird. Wenn sie immer noch übereinstimmt"line"
, verzweigt sie zum:x
Label zurück (das ist es, was diesbx
tut), fügt dem Puffer eine weitere Zeile hinzu und beginnt mit der Verarbeitung.quelle
sed
wo die Handhabung von Nicht-POSIX-Etiketten weit genug geht, um ein Leerzeichen als Trennzeichen für die Etikettendeklaration zu akzeptieren. Sie sollten jedoch beachten, dass jeder andere dortsed
scheitern wird - und für scheitern wirdN
. GNUsed
verstößt gegen die POSIX-Richtlinien zum Drucken des Musterbereichs vor dem Beenden inN
der letzten Zeile. POSIX macht jedoch deutlich, dass beimN
Lesen eines Befehls in der letzten Zeile nichts gedruckt werden sollte.v
Befehl von GNU zu lernen, der sich gegenseitigsed
unterbricht, in GNU-Versionen 4 und höher jedoch nicht verfügbar ist.sed -e :x -e '/"line"/{$!N' -e '};s/"line"\n<second>/other characters/;/"line"/bx'
.