Kann sed neue Zeilenzeichen ersetzen?

42

Gibt es ein Problem mit sed und New Line Character?
Ich habe eine Datei test.txt mit folgendem Inhalt

aaaaa  
bbbbb  
ccccc  
ddddd  

Folgendes funktioniert nicht:
sed -r -i 's/\n/,/g' test.txt

Ich weiß, dass ich das verwenden kann, traber meine Frage ist, warum es mit sed nicht möglich scheint.

Wenn dies ein Nebeneffekt der zeilenweisen Verarbeitung der Datei ist, würde mich interessieren, warum dies geschieht. Ich denke, grepneue Zeilen entfernt. Macht sed dasselbe?

Jim
quelle
1
In diesem Fall ist sed möglicherweise nicht das beste Werkzeug (z. B. "tr"). Es gibt Tools, die intuitiver sind, einfacher zu lesen / zu warten sind, eine bessere Leistung erzielen (insbesondere bei großen Datenmengen) usw. Verwenden Sie nicht Ihren Hammer, um die Schrauben einzusetzen (auch wenn es funktioniert). Sie finden einen Vergleich unter: http://slash4.de/blog/python/sed-replace-newline-or-python-awk-tr-perl-xargs.html
omoser
2
tr,Füge ein Trailing hinzu und gebe eine nicht abgeschlossene Zeile aus. Am besten verwenden Sie pastestattdessen:paste -sd , test.txt
Stéphane Chazelas

Antworten:

48

Mit GNU sedund POSIXLY_CORRECTnicht in der Umgebung bereitgestellt (für einzeilige Eingabe):

sed -i ':a;N;$!ba;s/\n/,/g' test.txt

Von https://stackoverflow.com/questions/1251999/sed-how-can-i-replace-a-newline-n :

  1. Erstellen Sie ein Label über :a
  2. Fügen Sie die aktuelle und nächste Zeile über an den Musterbereich an N
  3. Wenn wir uns vor der letzten Zeile befinden, verzweigen Sie zum erstellten Etikett $!ba( $!bedeutet, dass Sie dies nicht in der letzten Zeile tun müssen (da es eine letzte neue Zeile geben sollte)).
  4. Schließlich ersetzt die Ersetzung jede neue Zeile durch ein Komma im Musterbereich (das ist die gesamte Datei).
Anthon
quelle
Dies scheint darauf hinzudeuten, dass das Problem darin besteht, dass sed Zeile für Zeile liest. Aber ich kann nicht verstehen, warum dies ein Problem ist. Es könnte einfach die Zeile lesen und das neue Zeilenzeichen (oder das letzte Zeichen) durch ein,
Jim
1
@jim Es sieht so aus, als ob es nicht im Puffer ist, um verglichen zu werden, aber ich bin nicht fließend mit sed, vielleicht kann jemand anderes Licht ins Dunkel bringen. Ich denke, Sie sollten Ihr Q mit diesen spezifischen Informationen erweitern, damit die Leute es mit größerer Wahrscheinlichkeit lesen und hoffentlich antworten.
Anthon
Dies führt zuba: Event not found
krb686
@ krb686 Was ist das "Dies", auf das Sie sich beziehen? Haben Sie den obigen sedBefehl mit genau diesen Optionen ausgeführt? In welcher test.txt Datei? Mit welcher Version von sed(try sed --version)?
Anthon
@Anthon Sorry, ich glaube ich wollte "the" sagen. Ich habe einen weiteren SO-Post gelesen, der mich darüber informierte, dass csh mich dazu zwingt, dem zu entkommen !. Interessanterweise hat das bei mir immer noch nicht funktioniert und ich musste das !in meinem .cshDrehbuch verdoppeln . Ich habe im Moment kein wirkliches Problem, aber wissen Sie, warum das so sein könnte? Was für mich funktioniert hat warsed :a;N;$\\!ba;s/\n/ /g'
krb686
16

Dies funktioniert mit GNU sed:

sed -z 's/\n/,/g' 

-z ist enthalten seit 4.2.2

NB. -zÄndert das Trennzeichen in Nullzeichen ( \0). Wenn Ihre Eingabe keine Nullzeichen enthält, wird die gesamte Eingabe als einzelne Zeile behandelt. Dies kann mit Einschränkungen verbunden sein .

Um zu vermeiden, dass die neue Zeile der letzten Zeile ersetzt wird, können Sie sie zurücksetzen:

sed -z 's/\n/,/g;s/,$/\n/'

(Das ist wieder die GNU- sedSyntax, aber das macht nichts, da das Ganze nur GNU ist.)

Hielke Walinga
quelle
3
Dadurch wird auch die nachgestellte Zeile ersetzt, die möglicherweise nicht den Anforderungen von OP entspricht. Vergleichen Sie das Ergebnis mit der Lösung von mikeserv .
don_crissti
7

Von der Oracle-Website:

Das sed-Dienstprogramm liest nacheinander eine Datei Zeile für Zeile in den Speicher. Anschließend führt er alle für die Zeile angegebenen Aktionen aus und legt die Zeile zurück in den Speicher, um sie mit den angeforderten Änderungen im Terminal abzulegen. Nachdem alle Aktionen für diese eine Zeile ausgeführt wurden, wird die nächste Zeile der Datei gelesen und der Vorgang wiederholt, bis die Datei fertig ist.

Grundsätzlich bedeutet dies, dass das Zeilenumbruchzeichen nicht übereinstimmt, da sed zeilenweise liest.

Die Lösung von https://stackoverflow.com/questions/1251999/sed-how-can-i-replace-a-newline-n lautet:

sed ':a;N;$!ba;s/\n/,/g'

oder, in einer portablen Version (ohne ;Verkettung nach Sprungmarkenbeschriftungen)

sed -e ':a' -e 'N;$!ba' -e 's/\n/,/g'

Eine Erklärung dazu finden Sie auf dieser Seite.

user204992
quelle
Ich habe eine modifizierte Form verwendet, um VPN-Protokolle zu analysieren und den Benutzer "authentifiziert" und die Zeitstempelinformationen in dieselbe Zeile zu setzen. Prost!
user208145
Beachten Sie, dass diese Syntax GNU-spezifisch ist. sedWenn POSIXLY_CORRECT in der Umgebung vorhanden ist und die Eingabe nur eine Zeile enthält, erfolgt keine Ausgabe.
Stéphane Chazelas
5

sed\nEntfernt die nachgestellte ewline immer unmittelbar vor dem Auffüllen des Musterbereichs und hängt sie an, bevor die Ergebnisse des Skripts geschrieben werden. Eine \newline kann auf verschiedene Weise im Pattern-Space vorhanden sein - aber niemals, wenn sie nicht das Ergebnis einer Bearbeitung ist. Dies ist wichtig - \nE-Linien im sedMusterbereich spiegeln immer eine Änderung wider und treten niemals im Eingabestream auf. \newlines sind die einzigen Begrenzer, auf die sich ein Benutzer sedbei unbekannter Eingabe verlassen kann.

Wenn Sie alle \newlines durch Kommas ersetzen möchten und Ihre Datei nicht sehr groß ist, können Sie Folgendes tun:

sed 'H;1h;$!d;x;y/\n/,/'

Damit wird jede Eingabezeile nach einem ewline-Zeichen an das halte Leerzeichen angehängt - mit Ausnahme der ersten, die stattdessen das halte Leerzeichen überschreibt \n. Anschließend wird djede Zeile, die nicht die $!letzte ist, aus der Ausgabe gelöscht . In der letzten Zeile werden Halte und Muster-Leerzeichen xgeändert und alle \newline-Zeichen y///in Kommas übersetzt.

Bei großen Dateien führt dies zwangsläufig zu Problemen mit seddem Puffer an den Zeilengrenzen, die mit Aktionen dieser Art leicht überlaufen werden können.

mikeserv
quelle
2

Alternativ können Sie eine etwas einfachere Syntax verwenden:

sed ':a;N;s/\n/,/g;ba'

... einfach die Reihenfolge ändern.

Rodec
quelle
3
Führt den sBefehl jedoch für jede Eingabezeile in einem Musterbereich aus, der immer größer wird.
Stéphane Chazelas
1

Es gibt einige sehr schöne sed Magie hier. Und einige gute Punkte zum Musterraumüberlauf. Ich liebe es, sed zu verwenden, auch wenn es nicht der einfachste Weg ist, weil es so kompakt und leistungsstark ist. Es hat jedoch seine Grenzen und für große Datenmengen müsste der Musterraum mahoosiv sein.

GNU sagt dies:

Für diejenigen, die portable sed-Skripte schreiben möchten, ist zu beachten, dass es bekannt ist, dass einige Implementierungen die Zeilenlängen (für das Muster und die Leerzeichen) auf nicht mehr als 4000 Byte beschränken. Der posix-Standard gibt an, dass konforme sed-Implementierungen mindestens 8192-Byte-Zeilenlängen unterstützen müssen. GNU sed hat keine eingebaute Begrenzung der Leitungslänge; Solange es mehr (virtuellen) Speicher malloc () kann, können Sie Zeilen füttern oder konstruieren, so lange Sie möchten.
Rekursion wird jedoch verwendet, um Teilmuster und unbestimmte Wiederholungen zu behandeln. Dies bedeutet, dass der verfügbare Stapelspeicherplatz möglicherweise die Größe des Puffers begrenzt, der von bestimmten Mustern verarbeitet werden kann.

Ich habe nicht viel hinzuzufügen, aber ich möchte Sie auf meinen Reiseführer für sed hinweisen . Es ist exzellent. http://www.grymoire.com/Unix/Sed.html

Und hier ist meine Lösung:

for i in $(cat test.txt); do echo -n $i','; done; echo '' >> somewhere

Nun, es funktioniert

xeuari
quelle
-1

Angenommen, Sie möchten Zeilenumbrüche durch ersetzen \n. Das wollte ich tun, also habe ich Folgendes getan:

(echo foo; echo bar; echo baz) | sed -r '$!s/$/\\n/' | tr -d '\n' 
# Output: foo\nbar\nbaz

Hier ist, was es tut: für alle Zeilen mit Ausnahme der letzten , anhängen \n. Dann löschen Sie Zeilenumbrüche mit tr.

Camilo Martin
quelle
-rist nur in GNU verfügbar sed, nicht in BSD.
Kenorb