trist nur dann das richtige Werkzeug für den Job, wenn ein einzelnes Zeichen durch ein einzelnes Zeichen ersetzt wird, während das obige Beispiel zeigt, wie Zeilenumbrüche durch Leerzeichen ersetzt werden. Im obigen Beispiel könnte tr funktionieren. Dies würde jedoch später einschränken.
Wütend 84
9
trim richtigen Werkzeug für den Job, weil der Fragesteller jede neue Zeile durch ein Leerzeichen ersetzen wollte, wie in seinem Beispiel gezeigt. Das Ersetzen von Zeilenumbrüchen ist einzigartig geheimnisvoll, sedaber leicht zu erledigen tr. Dies ist eine häufige Frage. Das Durchführen von Regex-Ersetzungen erfolgt nicht durch, trsondern durch sed, was das richtige Werkzeug wäre ... für eine andere Frage.
Mike S
3
"tr" kann auch nur die neue Zeile "tr -d" \ n "löschen. Sie können jedoch auch Rückgaben löschen, um universeller" tr -d "\ 012 \ 015" zu sein.
Anthony
2
WARNUNG: "tr" verhält sich in Bezug auf Zeichenbereiche zwischen Linux und älteren Solaris-Computern (EG sol5.8) unterschiedlich. EG: "tr-d" az "und" tr-d "[az]". Dafür empfehle ich Ihnen "sed" zu verwenden, was diesen Unterschied nicht hat.
Anthony
2
@ MikeS Danke für die Antwort. Folgen Sie tr '\012' ' 'mit einem echo. Andernfalls wird auch der letzte Zeilenvorschub in der Datei gelöscht. tr '\012' ' ' < filename; echomacht den Trick.
Bernie Reiter
Antworten:
1513
Verwenden Sie diese Lösung mit GNU sed:
sed ':a;N;$!ba;s/\n/ /g' file
Dadurch wird die gesamte Datei in einer Schleife gelesen und die neue (n) Zeile (n) durch ein Leerzeichen ersetzt.
Erläuterung:
Erstellen Sie ein Etikett über :a.
Hängen Sie die aktuelle und die nächste Zeile über an den Musterbereich an N.
Wenn wir uns vor der letzten Zeile befinden, verzweigen Sie zum erstellten Label $!ba( $!bedeutet, dass Sie dies nicht in der letzten Zeile tun, da es eine letzte neue Zeile geben sollte).
Schließlich ersetzt die Ersetzung jede neue Zeile durch ein Leerzeichen im Musterbereich (der die gesamte Datei darstellt).
Hier ist eine plattformübergreifende kompatible Syntax, die mit BSD und OS X funktioniert sed(gemäß @ Benjie-Kommentar ):
sed -e ':a' -e 'N' -e '$!ba' -e 's/\n/ /g' file
Wie Sie sehen können, ist die Verwendung sedfür dieses ansonsten einfache Problem problematisch. Eine einfachere und adäquate Lösung finden Sie in dieser Antwort .
@Arjan und Masi: OS X verwendet BSDs sedanstelle von GNU sed, daher kann es einige subtile (und einige nicht so subtile) Unterschiede zwischen den beiden geben. Dies ist ein ständiger Schmerz, wenn Sie sowohl auf OS X- als auch auf * nix-Computern arbeiten. Normalerweise installiere ich GNUs coreutilsund findutilsunter OS X und ignoriere die BSD-Versionen.
Telemachos
50
Das :aist kein Register, es ist ein Zweigstellenlabel. Es ist ein Ziel für den bBefehl *, der wie "goto" funktioniert. Wenn Sie es als Register bezeichnen, können Sie Speicherorte erstellen. Es gibt nur zwei "Register"; Einer wird als "Haltebereich" bezeichnet, den Ihr Skript nicht verwendet, und der andere wird als "Musterbereich" bezeichnet. Der NBefehl hängt eine neue Zeile und die nächste Zeile der Eingabedatei an den Musterbereich an. [* Sie können mehrere Beschriftungen und bBefehle haben. Wenn Sie einen bBefehl ohne angehängtes Label char haben, verzweigt er sich zum Ende des Skripts, um die nächste Zeile zu lesen und die Schleife erneut
durchzuführen
108
Sie können diese plattformübergreifende Ausführung (dh unter Mac OS X) ausführen, indem Sie die Befehle separat ausführen, anstatt sie durch Semikolons zu trennen: sed -e ':a' -e 'N' -e '$!ba' -e 's/\n/ /g'
Benjie
74
Warum kommentiert niemand, was für ein dummes Durcheinander das ist (nicht die Antwort selbst, sondern das Programm, für das die vorgeschlagene Antwort die beste Lösung für ein sehr einfaches Problem ist). Sed sieht aus wie ein Auto, das normalerweise gut fährt. Wenn Sie jedoch zu einer bestimmten Straße in der Nähe fahren möchten, können Sie das Auto nur mit einem Hubschrauber anheben.
Ark-Kun
12
Komm schon Leute - 261 Gegenstimmen für eine verrückte, unverständliche Lösung, die nicht funktioniert ???? sed ist ein hervorragendes Werkzeug für einfache Unterteilungen in einer einzelnen Zeile, für alles andere verwenden Sie einfach awk. Gute Trauer ....
Ed Morton
1711
sedist für die zeilenbasierte Eingabe vorgesehen. Obwohl es tun kann, was Sie brauchen.
Eine bessere Option ist, den trBefehl wie folgt zu verwenden:
tr '\n' ' ' < input_filename
oder entfernen Sie die Zeilenumbruchzeichen vollständig:
tr -d '\n' < input.txt > output.txt
oder wenn Sie die GNU-Version haben (mit ihren langen Optionen)
Sed ist linienbasiert, daher ist es schwierig, Zeilenumbrüche zu erfassen.
Alexander Gladysh
191
sed arbeitet mit einem "Strom" von Eingaben, versteht es jedoch in durch Zeilenumbrüche getrennten Abschnitten. Es ist ein Unix-Tool, was bedeutet, dass es eine Sache sehr gut macht. Die eine Sache ist "zeilenweise an einer Datei arbeiten". Es wird schwierig sein, etwas anderes zu tun, und es besteht die Gefahr, dass es fehlerhaft ist. Die Moral der Geschichte lautet: Wählen Sie das richtige Werkzeug. Viele Ihrer Fragen scheinen die Form zu haben: "Wie kann ich dieses Tool dazu bringen, etwas zu tun, für das es nie gedacht war?" Diese Fragen sind interessant, aber wenn sie im Zuge der Lösung eines echten Problems auftauchen, machen Sie es wahrscheinlich falsch.
dmckee --- Ex-Moderator Kätzchen
7
@JBBrown trist ein oft übersehenes Juwel für den Bau von Pipelines.
dmckee --- Ex-Moderator Kätzchen
70
tr ist großartig, aber Sie können Zeilenumbrüche nur durch einzelne Zeichen ersetzen. Sie müssen ein anderes Werkzeug verwenden, wenn Sie Zeilenumbrüche durch eine Zeichenfolge ersetzen möchten
Eddy
21
@Eddy - Ich habe tr verwendet, um neue Zeilen durch ein Zeichen zu ersetzen, das nicht im Text enthalten war (ich habe Backtick verwendet), und dann sed, um den Backtick durch die Zeichenfolge zu ersetzen, die ich verwenden wollte
rjohnston
494
Schnelle Antwort
sed ':a;N;$!ba;s/\n/ /g' file
: a Erstelle ein Label 'a'
N Fügen Sie die nächste Zeile an den Musterbereich an
$! wenn nicht die letzte Zeile , ba Zweig (go to) Label 'a'
s Ersatz , / \ n / Regex für neue Zeile , / / durch ein Leerzeichen , / g globale Übereinstimmung (so oft es geht)
sed durchläuft die Schritte 1 bis 3, bis die letzte Zeile erreicht ist, wobei alle Zeilen in den Musterbereich passen, in dem sed alle \ n Zeichen ersetzt
Alternativen
Im Gegensatz zu sed müssen alle Alternativen nicht die letzte Zeile erreichen, um den Prozess zu starten
mit Bash , langsam
while read line;do printf "%s""$line ";done< file
mit perl , sed- ähnlicher Geschwindigkeit
perl -p -e 's/\n/ /' file
mit tr , schneller als sed , kann nur durch ein Zeichen ersetzt werden
tr '\n'' '< file
mit Einfügen , tr- ähnliche Geschwindigkeit, kann nur durch ein Zeichen ersetzt werden
paste -s -d ' ' file
mit awk , tr- ähnlicher Geschwindigkeit
awk 1 ORS=' ' file
Eine andere Alternative wie "echo $ (<Datei)" ist langsam, funktioniert nur bei kleinen Dateien und muss die gesamte Datei verarbeiten, um den Prozess zu starten.
5.10. Warum kann ich eine neue Zeile nicht mit der Escape-
Sequenz \ n abgleichen oder löschen ? Warum kann ich mit \ n nicht zwei oder mehr Zeilen abgleichen?
Das \ n wird niemals mit der neuen Zeile am
Zeilenende übereinstimmen , da die neue Zeile immer entfernt wird, bevor die Zeile in den
Musterbereich eingefügt wird . Verwenden Sie
den Befehl 'N' oder ähnliches (z. B. 'H; ...; g;'), um zwei oder mehr Zeilen in den Musterraum zu bringen .
Sed funktioniert folgendermaßen: sed liest jeweils eine Zeile,
schneidet die abschließende neue Zeile ab , fügt die verbleibenden Elemente in den Musterbereich ein, in dem
das sed-Skript sie adressieren oder ändern kann, und
hängt beim Drucken des Musterbereichs eine neue Zeile an stdout an (oder zu einer Datei). Wenn der
Musterbereich mit 'd' oder 'D' ganz oder teilweise gelöscht wird,
wird in solchen Fällen die neue Zeile nicht hinzugefügt. So mögen Skripte
sed 's/\n//' file # to delete newlines from each line
sed 's/\n/foo\n/' file # to add a word to the end of each line
funktioniert NIEMALS, da die nachfolgende neue
Zeile entfernt wird, bevor die Zeile in den Musterbereich eingefügt wird .
Verwenden Sie stattdessen eines der folgenden Skripte, um die oben genannten Aufgaben auszuführen :
tr -d '\n'< file # use tr to delete newlines
sed ':a;N;$!ba;s/\n//g' file # GNU sed to delete newlines
sed 's/$/ foo/' file # add "foo" to end of each line
Da andere Versionen von sed als GNU sed die Größe des Musterpuffers einschränken
, ist hier das Unix-Dienstprogramm 'tr' zu bevorzugen.
Wenn die letzte Zeile der Datei eine neue Zeile enthält, fügt GNU sed
diese neue Zeile zur Ausgabe hinzu, löscht jedoch alle anderen, während tr
alle neuen Zeilen löscht.
Um einen Block mit zwei oder mehr Zeilen abzugleichen, gibt es drei grundlegende Möglichkeiten:
(1) Verwenden Sie den Befehl 'N', um die nächste Zeile zum Musterbereich hinzuzufügen.
(2) Verwenden Sie den Befehl 'H' mindestens zweimal, um die aktuelle Zeile
an den Haltebereich anzuhängen , und rufen Sie dann die Zeilen
mit x, g oder G aus dem Haltebereich ab . oder (3) Adressbereiche verwenden (siehe Abschnitt 3.3 oben)
, um Zeilen zwischen zwei angegebenen Adressen abzugleichen.
Durch Auswahl von (1) und (2) wird ein \ n in den Musterraum
eingefügt , wo es wie gewünscht adressiert werden kann ('s / ABC \ nXYZ / alphabet / g'). Ein Beispiel
für die Verwendung von 'N' zum Löschen eines Zeilenblocks finden Sie in Abschnitt 4.13
("Wie lösche ich einen Block bestimmter aufeinanderfolgender Zeilen?"). Dieses
Beispiel kann geändert werden, indem der Löschbefehl in etwas
anderes geändert wird , z. B. 'p' (Drucken), 'i' (Einfügen), 'c' (Ändern), 'a' (Anhängen)
oder 's' (Ersetzen). .
Mit Auswahl (3) wird kein \ n in den Musterbereich eingefügt, es stimmt jedoch
mit einem Block aufeinanderfolgender Zeilen überein. Daher
benötigen Sie möglicherweise nicht einmal das \ n, um das Gesuchte zu finden. Seit GNU sed unterstützt
Version 3.02.80 diese Syntax:
sed '/start/,+4d'# to delete "start" plus the next 4 lines,
Zusätzlich zu den herkömmlichen Bereichsadressen '/ from here /, / to there / {...}'
kann die Verwendung von \ n möglicherweise vollständig vermieden werden.
Das Beste an dieser Antwort ist, dass die "lange Antwort" genau erklärt, wie und warum der Befehl funktioniert.
pdwalker
3
Dies ist möglicherweise die hilfreichste der Tausenden von Antworten, die ich bei Stackexchange gelesen habe. Ich muss mehrere Zeichen über Zeilen hinweg abgleichen. Keine früheren sed-Beispiele deckten mehrere Zeilen ab, und tr kann keine Mehrfachzeichenübereinstimmung verarbeiten. Perl sieht gut aus, funktioniert aber nicht wie erwartet. Ich würde diese Antwort mehrmals abstimmen, wenn ich könnte.
Mightypile
225
Eine kürzere awk Alternative:
awk 1 ORS=' '
Erläuterung
Ein awk-Programm besteht aus Regeln, die aus bedingten Codeblöcken bestehen, dh:
condition { code-block }
Wenn der Codeblock weggelassen wird, wird die Standardeinstellung verwendet : { print $0 }. Somit wird das 1als eine wahre Bedingung interpretiert und print $0für jede Zeile ausgeführt.
Wenn awkdie Eingabe gelesen wird, wird sie basierend auf dem Wert von RS(Datensatztrennzeichen), der standardmäßig eine neue Zeile ist, in Datensätze aufgeteilt. Daher awkwird die Eingabe standardmäßig zeilenweise analysiert. Bei der Aufteilung wird auch RSder Eingabedatensatz entfernt.
Wenn nun ein Datensatz gedruckt wird ORS(Output Record Separator), wird standardmäßig wieder eine neue Zeile eingefügt. ORSWenn Sie also zu einem Leerzeichen wechseln , werden alle Zeilenumbrüche in Leerzeichen geändert.
Ich mag diese einfache Lösung, die viel besser lesbar ist, sehr als andere
Fedir RYKHTIK
8
Wenn es sinnvoller ist, könnte dies effektiv geschrieben werden als: awk 'BEGIN { ORS=" " } { print $0 } END { print "\n"} ' file.txt(Hinzufügen einer neuen Endzeile, um Anfang / Ende zu veranschaulichen); Die "1" ergibt true(Zeile verarbeiten) und print(Zeile drucken). Zu diesem Ausdruck könnte auch eine Bedingung hinzugefügt werden, z. B. nur die Bearbeitung von Linien, die einem Muster entsprechen: awk 'BEGIN { ORS=" " } /pattern/ { print $0 } END { print "\n"} '
Michael
2
Sie können es einfacher machen: codeawk 'ORS = ""' file.txtcode
Udi
Wenn Sie awk wie dieses verwenden, wird leider auch der letzte Zeilenvorschub in der Datei gelöscht. Siehe Patrick Dark Antwort oben über die Verwendung von 'tr' in einer Unterschale wie 'cat file | echo $ (tr "\ 012" "") `was den Trick macht. Raffiniert.
Bernie Reiter
143
gnu sed hat eine Option -zfür null getrennte Datensätze (Zeilen). Sie können einfach anrufen:
Selbst wenn die Eingabe Nullen enthält, bleiben diese erhalten (als Datensatzbegrenzer).
Toby Speight
6
Wird dadurch nicht die gesamte Eingabe geladen, wenn keine Nullen vorhanden sind? In diesem Fall kann die Verarbeitung einer Multi-Gigabyte-Datei abstürzen.
Ruslan
3
@ Ruslan, ja, es lädt die gesamte Eingabe. Diese Lösung ist keine gute Idee für Multi-Gigabyte-Dateien.
JJoao
7
Dies ist im Ernst die beste Antwort. Die anderen Ausdrücke sind zu verzerrt, um sich zu erinnern. @JJoao Sie können es mit verwenden -u, --unbuffered. Der manMagier sagt: "Laden Sie minimale Datenmengen aus den Eingabedateien und leeren Sie die Ausgabepuffer häufiger."
Wie in den Kommentaren erwähnt, ist es erwähnenswert, dass diese Änderungen vorgenommen wurden. -i.bakSie erhalten vor dem Ersetzen eine Sicherungskopie der Originaldatei, falls Ihr regulärer Ausdruck nicht so intelligent ist, wie Sie gedacht haben.
Bitte erwähnen Sie zumindest, dass -iohne Suffix keine Sicherung erfolgt . -i.bakschützt Sie vor einem einfachen, hässlichen Fehler (z. B. vergessen -p, die Datei einzugeben und auf Null zu setzen).
Telemachos
6
@ Telemachus: Es ist ein fairer Punkt, aber es kann so oder so argumentiert werden. Der Hauptgrund, warum ich es nicht erwähnt habe, ist, dass das sed-Beispiel in der OP-Frage keine Backups erstellt, sodass es hier überflüssig erscheint. Der andere Grund ist, dass ich die Sicherungsfunktion noch nie verwendet habe (ich finde automatische Sicherungen eigentlich ärgerlich), daher vergesse ich immer, dass sie vorhanden ist. Der dritte Grund ist, dass meine Befehlszeile um vier Zeichen länger wird. Zum Guten oder Schlechten (wahrscheinlich zum Schlechten) bin ich ein zwanghafter Minimalist; Ich bevorzuge nur die Kürze. Mir ist klar, dass Sie nicht einverstanden sind. Ich werde mein Bestes geben, um mich daran zu erinnern, in Zukunft vor Backups zu warnen.
ire_and_curses
6
@Ire_and_curses: Eigentlich hast du gerade ein verdammt gutes Argument dafür gemacht, mich zu ignorieren. Das heißt, Sie haben Gründe für Ihre Entscheidungen, und ob ich mit den Entscheidungen einverstanden bin oder nicht, ich respektiere das mit Sicherheit. Ich bin mir nicht ganz sicher, warum, aber ich habe in letzter Zeit eine Träne über diese bestimmte Sache (die -iFlagge in Perl ohne Suffix). Ich bin sicher, ich werde bald etwas anderes finden, von dem ich besessen sein kann. :)
Telemachos
Es ist wirklich bedauerlich, dass dies mit stdin nicht funktioniert, wenn Sie den -Dateinamen angeben. Gibt es eine Möglichkeit, das zu tun? Das ist meine Vorgehensweise, um mir keine Sorgen über das Ändern einer Datei zu machen, indem ich eine Pipeline verwende, die mit cat beginnt.
Steven Lu
@StevenLu Perl liest standardmäßig aus STDIN, wenn keine Dateinamen angegeben sind. So könnten Sie zBperl -i -p -e 's/\n//' < infile > outfile
ire_and_curses
44
Wer braucht sed? Hier ist der bashWeg:
cat test.txt | while read line; do echo -n "$line "; done
Upvote, ich habe normalerweise die Top-Antwort verwendet, aber wenn ich / dev / urandom durchpfeife, wird sed erst mit EOF gedruckt, und ^ C ist kein EOF. Diese Lösung wird jedes Mal gedruckt, wenn eine neue Zeile angezeigt wird. Genau das, was ich brauchte! Vielen Dank!
oder einfach, tr -d '\n'wenn Sie kein Leerzeichen hinzufügen möchten
Spuder
21
Drei Dinge.
tr(oder catusw.) wird absolut nicht benötigt. (GNU) sedund (GNU) awkkönnen in Kombination 99,9% aller benötigten Textverarbeitungen ausführen.
stream! = zeilenbasiert. edist ein zeilenbasierter Editor. sedist nicht. Siehe sed Vortrag , um weitere Informationen über den Unterschied. Die meisten Leute verwechseln seddie Zeilenorientierung , da die Musterübereinstimmung für EINFACHE Übereinstimmungen standardmäßig nicht sehr gierig ist. Wenn Sie beispielsweise Muster suchen und durch ein oder zwei Zeichen ersetzen, wird sie standardmäßig nur bei der ersten Übereinstimmung ersetzt es findet (sofern im globalen Befehl nicht anders angegeben). Es würde nicht einmal einen globalen Befehl geben, wenn er eher zeilenbasiert als STREAM-basiert wäre, da nur Zeilen gleichzeitig ausgewertet würden. Versuche zu rennen ed; Sie werden den Unterschied bemerken. edist ziemlich nützlich, wenn Sie über bestimmte Zeilen iterieren möchten (z. B. in einer for-Schleife), aber meistens nur sed.
Davon abgesehen,
sed -e '{:q;N;s/\n/ /g;t q}' file
funktioniert gut in GNU sedVersion 4.2.1. Der obige Befehl ersetzt alle Zeilenumbrüche durch Leerzeichen. Es ist hässlich und etwas umständlich einzutippen, aber es funktioniert gut. Die {}können weggelassen werden, da sie nur aus Gründen der Vernunft enthalten sind.
Als eine Person, die nur genug weiß sed, um grundlegende Dinge zu tun, muss ich sagen, dass es mehr als nur darum geht, was man damit machen kann , sedsondern vielmehr darum , wie einfach es ist, zu verstehen, was los ist. Es fällt mir sehr schwer, damit zu arbeiten, seddaher würde ich einen einfacheren Befehl bevorzugen, wenn ich ihn verwenden kann.
Nate
Unter Verwendung t qals bedingter Sprung dies funktioniert mit einem Muster wie s/\n / /(alle Linien zu verbinden , die mit einem Leerzeichen beginnen) , ohne die gesamte Datei in dem Speicher zu lesen. Praktisch beim Transformieren von Multi-Megabyte-Dateien.
Textshell
Der Artikel, den Sie verlinkt haben, spiegelt nicht wider, was Sie sagen
hek2mgl
Dies ist fast 800-mal langsamer als die akzeptierte Antwort bei großen Eingaben. Dies ist darauf zurückzuführen, dass bei immer größeren Eingaben für jede Zeile ein Ersatz ausgeführt wird.
Ein subtiler Hinweis zur Nomenklatur: Das Zeichen \000wird allgemein als NUL(ein L) bezeichnet und NULLwird im Allgemeinen verwendet, wenn von einem Nullzeiger gesprochen wird (in C / C ++).
Ich bin kein Experte, aber ich denke, sedSie müssten zuerst die nächste Zeile in den Musterraum einfügen, indem Sie " N" verwenden. Aus dem Abschnitt "Multiline Pattern Space" in "Advanced sed Commands" des Buches sed & awk (Dale Dougherty und Arnold Robbins; O'Reilly 1997; Seite 107 in der Vorschau ):
Der mehrzeilige Next (N) -Befehl erstellt einen mehrzeiligen Musterraum, indem eine neue Eingabezeile gelesen und an den Inhalt des Musterraums angehängt wird. Der ursprüngliche Inhalt des Musterbereichs und die neue Eingabezeile werden durch eine neue Zeile getrennt. Das eingebettete Zeilenumbruchzeichen kann durch die Escape-Sequenz "\ n" in Mustern abgeglichen werden. In einem mehrzeiligen Musterraum entspricht das Metazeichen "^" dem allerersten Zeichen des Musterraums und nicht den Zeichen, die auf eingebettete Zeilenumbrüche folgen. In ähnlicher Weise stimmt "$" nur mit der letzten neuen Zeile im Musterbereich überein und nicht mit eingebetteten neuen Zeilen. Nachdem der Befehl Weiter ausgeführt wurde, wird die Steuerung an nachfolgende Befehle im Skript übergeben.
Von man sed:
[2addr] N.
Fügen Sie die nächste Eingabezeile mit einem eingebetteten Zeilenumbruchzeichen an den Musterbereich an, um das angehängte Material vom ursprünglichen Inhalt zu trennen. Beachten Sie, dass sich die aktuelle Zeilennummer ändert.
Ich habe dies verwendet , um (mehrere) schlecht formatierte Protokolldateien zu durchsuchen, in denen die Suchzeichenfolge möglicherweise in einer "verwaisten" nächsten Zeile gefunden wird.
Ich habe einen hybriden Ansatz verwendet, um die Newline-Sache zu umgehen, indem ich tr verwendet habe, um Newlines durch Tabs zu ersetzen, und dann Tabs durch alles ersetzt habe, was ich will. In diesem Fall " ", da ich versuche, HTML-Unterbrechungen zu generieren.
Als Antwort auf die obige "tr" -Lösung unter Windows (wahrscheinlich unter Verwendung der Gnuwin32-Version von tr) wurde die vorgeschlagene Lösung vorgeschlagen:
tr '\n' ' ' < input
funktionierte nicht für mich, es würde entweder einen Fehler machen oder das \ nw / '' aus irgendeinem Grund ersetzen.
Mit einer anderen Funktion von tr funktionierte die Option "Löschen" -d jedoch:
Unter Windows müssen Sie wahrscheinlich verwenden tr "\n" " " < input. Die Windows-Shell (cmd.exe) behandelt den Apostroph nicht als Anführungszeichen.
Keith Thompson
Nein, im Windows 10 Ubuntu-Subsystem müssen Sietr "\n\r" " " < input.txt > output.txt
user1491819
Dies funktioniert unter Windows 10 mit Gnuwin32 : cat SourceFile.txt | tr --delete '\r\n' > OutputFile.txt. Oder verwenden Sie anstelle von Gnuwin32 Gow (Gnu unter Windows), github.com/bmatzelle/gow/wiki
Alchemistmatt
5
Kugelsichere Lösung. Binärdatensicher und POSIX-kompatibel, aber langsam.
POSIX sed
erfordert eine Eingabe gemäß der
POSIX-Textdatei
und den
POSIX-
Zeilendefinitionen, sodass NULL-Bytes und zu lange Zeilen nicht zulässig sind und jede Zeile mit einer neuen Zeile (einschließlich der letzten Zeile) enden muss. Dies macht es schwierig, sed für die Verarbeitung beliebiger Eingabedaten zu verwenden.
Die folgende Lösung vermeidet sed und konvertiert stattdessen die eingegebenen Bytes in Oktalcodes und dann wieder in Bytes, fängt jedoch den Oktalcode 012 (Zeilenumbruch) ab und gibt stattdessen die Ersatzzeichenfolge aus. Soweit ich das beurteilen kann, ist die Lösung POSIX-kompatibel und sollte daher auf einer Vielzahl von Plattformen funktionieren.
od -A n -t o1 -v | tr ' \t' '\n\n' | grep . |
while read x; do [ "0$x" -eq 012 ] && printf '<br>\n' || printf "\\$x"; done
Beide read, [und printfsind zumindest in Bash integriert, aber das wird von POSIX wahrscheinlich nicht garantiert. Auf einigen Plattformen kann es daher sein, dass jedes Eingabebyte einen oder mehrere neue Prozesse startet, was die Arbeit verlangsamt. Selbst in Bash erreicht diese Lösung nur etwa 50 kB / s, daher ist sie nicht für große Dateien geeignet.
Getestet unter Ubuntu (Bash, Dash und Busybox), FreeBSD und OpenBSD.
In einigen Situationen können Sie möglicherweise RSzu einer anderen Zeichenfolge oder einem anderen Zeichen wechseln . Auf diese Weise ist \ n für sub / gsub verfügbar:
Die Stärke von Shell-Skripten besteht darin, dass Sie es auf andere Weise tun können, wenn Sie nicht wissen, wie es auf eine Weise zu tun ist. Und oft müssen Sie mehr Dinge berücksichtigen, als eine komplexe Lösung für ein einfaches Problem zu finden.
In Bezug auf die Sache, dass gawk langsam ist ... und die Datei in den Speicher liest, weiß ich das nicht, aber für mich scheint gawk mit jeweils einer Zeile zu arbeiten und ist sehr sehr schnell (nicht so schnell wie einige der anderen , aber auch die Zeit zum Schreiben und Testen zählt).
Ich verarbeite MB und sogar GB Daten, und die einzige Grenze, die ich gefunden habe, ist die Zeilengröße.
Dies wird [durch einen Raum und \rdurch einen Raum und \ndurch einen Raum und ]durch einen Raum ersetzt. tr -d '\r\n' <filewürde alle \roder \nZeichen entfernen , aber das ist auch nicht das, was gefragt wird. tr -d '\r' <fileentfernt alle \rZeichen (unabhängig davon, ob sie benachbart sind \n), was wahrscheinlich eher nützlich als möglicherweise für die Anforderungen des OP korrekt ist (vorausgesetzt, Sie trverstehen diese Backslash-Notation).
Tripleee
4
Sie können verwenden xargs- es wird \nstandardmäßig durch ein Leerzeichen ersetzt.
Es würde jedoch Probleme geben, wenn Ihre Eingabe einen Fall von a aufweist unterminated quote, z. B. wenn die Anführungszeichen in einer bestimmten Zeile nicht übereinstimmen.
echo "1\n2\n3" | awk '{printf $0}', das funktioniert bei mir. @ edi9999
Itachi
Es tut dir leid, ich habe das fin printf
edi9999
Dies war der einzige Ansatz, der für mich innerhalb von Git Bash für Windows funktioniert hat
Plato
3
Unter Mac OS X (mit FreeBSD sed):
# replace each newline with a space
printf "a\nb\nc\nd\ne\nf" | sed -E -e :a -e '$!N; s/\n/ /g; ta'
printf "a\nb\nc\nd\ne\nf" | sed -E -e :a -e '$!N; s/\n/ /g' -e ta
Sie müssen die Anführungszeichen und das Dollarzeichen nicht umgehen, wenn Sie die äußeren in einfache Anführungszeichen ändern. Der Buchstabe "o" wird normalerweise als schlechte Wahl als Variablenname angesehen, da er mit der Ziffer "0" verwechselt werden kann. Sie müssen Ihre Variable auch nicht initialisieren, sie ist standardmäßig eine Nullzeichenfolge. Wenn Sie jedoch keinen fremden führenden Raum wünschen : awk '{s = s sp $0; sp = " "} END {print s}'. In meiner Antwort finden Sie jedoch eine Möglichkeit, awk zu verwenden, ohne die gesamte Datei in den Speicher einzulesen.
Bis auf weiteres angehalten.
Bitte überprüfen Sie stattdessen Thors Antwort . Es ist viel effizienter, lesbarer und auf jeden Fall besser , diesen Ansatz zu vergleichen (obwohl dies funktionieren würde )!
Mschilli
Alter, ich verstehe. Keine Notwendigkeit, es mir ins Gesicht zu reiben :-) Thors Antwort ist sowieso weit oben auf der Seite (was richtig ist), also was kümmert es dich?
Kralyk
3
Eine Lösung, die mir besonders gefällt, besteht darin, die gesamte Datei im Haltebereich anzuhängen und alle Zeilenumbrüche am Ende der Datei zu ersetzen:
$ (echo foo; echo bar) | sed -n 'H;${x;s/\n//g;p;}'
foobar
Jemand sagte mir jedoch, dass der Haltebereich in einigen sed-Implementierungen begrenzt sein kann.
Die Ersetzung durch eine leere Zeichenfolge in Ihrer Antwort verbirgt die Tatsache, dass die Verwendung von H zum Anhängen an den Haltebereich bedeutet, dass der Haltebereich mit einer neuen Zeile beginnt. Um dies zu vermeiden, müssen Sie1h;2,$H;${x;s/\n/x/g;p}
Jeff
3
Ersetzen Sie Zeilenumbrüche durch eine beliebige Zeichenfolge und ersetzen Sie auch die letzte Zeilenumbruch
Die reinen trLösungen können nur durch ein einzelnes Zeichen ersetzt werden, und die reinen sedLösungen ersetzen nicht die letzte neue Zeile der Eingabe. Die folgende Lösung behebt diese Probleme und scheint für Binärdaten sicher zu sein (auch mit einem UTF-8-Gebietsschema):
printf '1\n2\n3\n' |
sed 's/%/%p/g;s/@/%a/g' | tr '\n' @ | sed 's/@/<br>/g;s/%a/@/g;s/%p/%/g'
Dies ist schlecht, weil es unerwünschte Ausgabe auf jeder Eingabe erzeugt, die enthält@
Steven Lu
@StevenLu: Nein, @in der Eingabe ist OK. Es wird hin %aund zurück entkommen . Die Lösung ist jedoch möglicherweise nicht vollständig POSIX-kompatibel (NULL-Bytes sind nicht zulässig, daher nicht gut für Binärdaten, und alle Zeilen müssen mit newline enden, damit die trAusgabe nicht wirklich gültig ist).
Håkon A. Hjortland
Ah. Ich sehe, du hast es repariert. Ein bisschen verworren für eine einfache Operation, aber gute Arbeit.
Steven Lu
3
Es ist sed , das die neuen Zeilen nach "normaler" Substitution einführt. Zuerst wird das Zeichen für die neue Zeile gekürzt, dann wird es gemäß Ihren Anweisungen verarbeitet, und dann wird eine neue Zeile eingeführt.
Mit sed können Sie "das Ende" einer Zeile (nicht das Zeichen für neue Zeilen) ersetzen, nachdem Sie für jede Eingabezeile eine Zeichenfolge Ihrer Wahl zugeschnitten haben. aber sed ausgeben werden verschiedene Linien. Angenommen, Sie möchten das "Zeilenende" durch "===" ersetzen (allgemeiner als das Ersetzen durch ein einzelnes Leerzeichen):
PROMPT~$ cat <<EOF |sed 's/$/===/g'
first line
second line
3rd line
EOF
first line===
second line===
3rd line===
PROMPT~$
Um das Zeichen für die neue Zeile durch die Zeichenfolge zu ersetzen, können Sie, wie bereits erwähnt, ineffizient tr verwenden , um die Zeichen für die neue Zeile durch ein "Sonderzeichen" zu ersetzen, und dann sed verwenden , um das Sonderzeichen durch die gewünschte Zeichenfolge zu ersetzen .
Zum Beispiel:
PROMPT~$ cat <<EOF | tr '\n' $'\x01'|sed -e 's/\x01/===/g'
first line
second line
3rd line
EOF
first line===second line===3rd line===PROMPT~$
x - which is used to exchange the data from both space (pattern and hold).
G - which is used to append the data from hold space to pattern space.
h - which is used to copy the pattern space to hold space.
1!h - During first line won't copy pattern space to hold space due to \n is
available in pattern space.
$!d - Clear the pattern space every time before getting next line until the
last line.
Ablauf:
Wenn die erste Zeile von der Eingabe stammt, wird ein Austausch durchgeführt, sodass 1 in den Speicherbereich geht und \ n in den Musterbereich gelangt. Anschließend wird der Haltebereich an den Musterbereich angehängt. Anschließend wird der Musterbereich ersetzt und gelöscht.
Während des Austauschs der zweiten Zeile wird 2 in den Haltebereich und 1 in den Musterbereich verschoben. Anschließend wird der GHaltebereich in den Musterbereich eingefügt, hdas Muster in diesen kopiert und ersetzt und gelöscht. Dieser Vorgang wird fortgesetzt, bis eof erreicht ist, und dann das genaue Ergebnis gedruckt.
Man würde hoffen, ydass es schneller läuft als s(vielleicht mit einer trGeschwindigkeit von 20x schneller), aber in GNU ist sed v4.2.2y ungefähr 4% langsamer als s.
tr
ist nur dann das richtige Werkzeug für den Job, wenn ein einzelnes Zeichen durch ein einzelnes Zeichen ersetzt wird, während das obige Beispiel zeigt, wie Zeilenumbrüche durch Leerzeichen ersetzt werden. Im obigen Beispiel könnte tr funktionieren. Dies würde jedoch später einschränken.tr
im richtigen Werkzeug für den Job, weil der Fragesteller jede neue Zeile durch ein Leerzeichen ersetzen wollte, wie in seinem Beispiel gezeigt. Das Ersetzen von Zeilenumbrüchen ist einzigartig geheimnisvoll,sed
aber leicht zu erledigentr
. Dies ist eine häufige Frage. Das Durchführen von Regex-Ersetzungen erfolgt nicht durch,tr
sondern durchsed
, was das richtige Werkzeug wäre ... für eine andere Frage.tr '\012' ' '
mit einemecho
. Andernfalls wird auch der letzte Zeilenvorschub in der Datei gelöscht.tr '\012' ' ' < filename; echo
macht den Trick.Antworten:
Verwenden Sie diese Lösung mit GNU
sed
:Dadurch wird die gesamte Datei in einer Schleife gelesen und die neue (n) Zeile (n) durch ein Leerzeichen ersetzt.
Erläuterung:
:a
.N
.$!ba
($!
bedeutet, dass Sie dies nicht in der letzten Zeile tun, da es eine letzte neue Zeile geben sollte).Hier ist eine plattformübergreifende kompatible Syntax, die mit BSD und OS X funktioniert
sed
(gemäß @ Benjie-Kommentar ):Wie Sie sehen können, ist die Verwendung
sed
für dieses ansonsten einfache Problem problematisch. Eine einfachere und adäquate Lösung finden Sie in dieser Antwort .quelle
sed
anstelle von GNUsed
, daher kann es einige subtile (und einige nicht so subtile) Unterschiede zwischen den beiden geben. Dies ist ein ständiger Schmerz, wenn Sie sowohl auf OS X- als auch auf * nix-Computern arbeiten. Normalerweise installiere ich GNUscoreutils
undfindutils
unter OS X und ignoriere die BSD-Versionen.:a
ist kein Register, es ist ein Zweigstellenlabel. Es ist ein Ziel für denb
Befehl *, der wie "goto" funktioniert. Wenn Sie es als Register bezeichnen, können Sie Speicherorte erstellen. Es gibt nur zwei "Register"; Einer wird als "Haltebereich" bezeichnet, den Ihr Skript nicht verwendet, und der andere wird als "Musterbereich" bezeichnet. DerN
Befehl hängt eine neue Zeile und die nächste Zeile der Eingabedatei an den Musterbereich an. [* Sie können mehrere Beschriftungen undb
Befehle haben. Wenn Sie einenb
Befehl ohne angehängtes Label char haben, verzweigt er sich zum Ende des Skripts, um die nächste Zeile zu lesen und die Schleife erneutsed -e ':a' -e 'N' -e '$!ba' -e 's/\n/ /g'
sed
ist für die zeilenbasierte Eingabe vorgesehen. Obwohl es tun kann, was Sie brauchen.Eine bessere Option ist, den
tr
Befehl wie folgt zu verwenden:oder entfernen Sie die Zeilenumbruchzeichen vollständig:
oder wenn Sie die GNU-Version haben (mit ihren langen Optionen)
quelle
tr
ist ein oft übersehenes Juwel für den Bau von Pipelines.Schnelle Antwort
sed durchläuft die Schritte 1 bis 3, bis die letzte Zeile erreicht ist, wobei alle Zeilen in den Musterbereich passen, in dem sed alle \ n Zeichen ersetzt
Alternativen
Im Gegensatz zu sed müssen alle Alternativen nicht die letzte Zeile erreichen, um den Prozess zu starten
mit Bash , langsam
mit perl , sed- ähnlicher Geschwindigkeit
mit tr , schneller als sed , kann nur durch ein Zeichen ersetzt werden
mit Einfügen , tr- ähnliche Geschwindigkeit, kann nur durch ein Zeichen ersetzt werden
mit awk , tr- ähnlicher Geschwindigkeit
Eine andere Alternative wie "echo $ (<Datei)" ist langsam, funktioniert nur bei kleinen Dateien und muss die gesamte Datei verarbeiten, um den Prozess zu starten.
Lange Antwort aus den sed FAQ 5.10
5.10. Warum kann ich eine neue Zeile nicht mit der Escape-
Sequenz \ n abgleichen oder löschen ? Warum kann ich mit \ n nicht zwei oder mehr Zeilen abgleichen?
Das \ n wird niemals mit der neuen Zeile am
Zeilenende übereinstimmen , da die neue Zeile immer entfernt wird, bevor die Zeile in den
Musterbereich eingefügt wird . Verwenden Sie
den Befehl 'N' oder ähnliches (z. B. 'H; ...; g;'), um zwei oder mehr Zeilen in den Musterraum zu bringen .
Sed funktioniert folgendermaßen: sed liest jeweils eine Zeile,
schneidet die abschließende neue Zeile ab , fügt die verbleibenden Elemente in den Musterbereich ein, in dem
das sed-Skript sie adressieren oder ändern kann, und
hängt beim Drucken des Musterbereichs eine neue Zeile an stdout an (oder zu einer Datei). Wenn der
Musterbereich mit 'd' oder 'D' ganz oder teilweise gelöscht wird,
wird in solchen Fällen die neue Zeile nicht hinzugefügt. So mögen Skripte
funktioniert NIEMALS, da die nachfolgende neue Zeile entfernt wird, bevor
die Zeile in den Musterbereich eingefügt wird .
Verwenden Sie stattdessen eines der folgenden Skripte, um die oben genannten Aufgaben auszuführen :
Da andere Versionen von sed als GNU sed die Größe des Musterpuffers einschränken
, ist hier das Unix-Dienstprogramm 'tr' zu bevorzugen.
Wenn die letzte Zeile der Datei eine neue Zeile enthält, fügt GNU sed
diese neue Zeile zur Ausgabe hinzu, löscht jedoch alle anderen, während tr
alle neuen Zeilen löscht.
Um einen Block mit zwei oder mehr Zeilen abzugleichen, gibt es drei grundlegende Möglichkeiten:
(1) Verwenden Sie den Befehl 'N', um die nächste Zeile zum Musterbereich hinzuzufügen.
(2) Verwenden Sie den Befehl 'H' mindestens zweimal, um die aktuelle Zeile
an den Haltebereich anzuhängen , und rufen Sie dann die Zeilen
mit x, g oder G aus dem Haltebereich ab . oder (3) Adressbereiche verwenden (siehe Abschnitt 3.3 oben)
, um Zeilen zwischen zwei angegebenen Adressen abzugleichen.
Durch Auswahl von (1) und (2) wird ein \ n in den Musterraum
eingefügt , wo es wie gewünscht adressiert werden kann ('s / ABC \ nXYZ / alphabet / g'). Ein Beispiel
für die Verwendung von 'N' zum Löschen eines Zeilenblocks finden Sie in Abschnitt 4.13
("Wie lösche ich einen Block bestimmter aufeinanderfolgender Zeilen?"). Dieses
Beispiel kann geändert werden, indem der Löschbefehl in etwas
anderes geändert wird , z. B. 'p' (Drucken), 'i' (Einfügen), 'c' (Ändern), 'a' (Anhängen)
oder 's' (Ersetzen). .
Mit Auswahl (3) wird kein \ n in den Musterbereich eingefügt, es stimmt jedoch
mit einem Block aufeinanderfolgender Zeilen überein. Daher
benötigen Sie möglicherweise nicht einmal das \ n, um das Gesuchte zu finden. Seit GNU sed unterstützt
Version 3.02.80 diese Syntax:
Zusätzlich zu den herkömmlichen Bereichsadressen '/ from here /, / to there / {...}'
kann die Verwendung von \ n möglicherweise vollständig vermieden werden.
quelle
tr
war eine großartige Idee, und Ihre Gesamtabdeckung sorgt für eine qualitativ hochwertige Antwort.paste
... und alle anderen!Eine kürzere awk Alternative:
Erläuterung
Ein awk-Programm besteht aus Regeln, die aus bedingten Codeblöcken bestehen, dh:
Wenn der Codeblock weggelassen wird, wird die Standardeinstellung verwendet :
{ print $0 }
. Somit wird das1
als eine wahre Bedingung interpretiert undprint $0
für jede Zeile ausgeführt.Wenn
awk
die Eingabe gelesen wird, wird sie basierend auf dem Wert vonRS
(Datensatztrennzeichen), der standardmäßig eine neue Zeile ist, in Datensätze aufgeteilt. Daherawk
wird die Eingabe standardmäßig zeilenweise analysiert. Bei der Aufteilung wird auchRS
der Eingabedatensatz entfernt.Wenn nun ein Datensatz gedruckt wird
ORS
(Output Record Separator), wird standardmäßig wieder eine neue Zeile eingefügt.ORS
Wenn Sie also zu einem Leerzeichen wechseln , werden alle Zeilenumbrüche in Leerzeichen geändert.quelle
awk 'BEGIN { ORS=" " } { print $0 } END { print "\n"} ' file.txt
(Hinzufügen einer neuen Endzeile, um Anfang / Ende zu veranschaulichen); Die "1" ergibttrue
(Zeile verarbeiten) undprint
(Zeile drucken). Zu diesem Ausdruck könnte auch eine Bedingung hinzugefügt werden, z. B. nur die Bearbeitung von Linien, die einem Muster entsprechen:awk 'BEGIN { ORS=" " } /pattern/ { print $0 } END { print "\n"} '
code
awk 'ORS = ""' file.txtcode
gnu sed hat eine Option
-z
für null getrennte Datensätze (Zeilen). Sie können einfach anrufen:quelle
-u, --unbuffered
. Derman
Magier sagt: "Laden Sie minimale Datenmengen aus den Eingabedateien und leeren Sie die Ausgabepuffer häufiger."Die Perl- Version funktioniert wie erwartet.
Wie in den Kommentaren erwähnt, ist es erwähnenswert, dass diese Änderungen vorgenommen wurden.
-i.bak
Sie erhalten vor dem Ersetzen eine Sicherungskopie der Originaldatei, falls Ihr regulärer Ausdruck nicht so intelligent ist, wie Sie gedacht haben.quelle
-i
ohne Suffix keine Sicherung erfolgt .-i.bak
schützt Sie vor einem einfachen, hässlichen Fehler (z. B. vergessen-p
, die Datei einzugeben und auf Null zu setzen).-i
Flagge in Perl ohne Suffix). Ich bin sicher, ich werde bald etwas anderes finden, von dem ich besessen sein kann. :)-
Dateinamen angeben. Gibt es eine Möglichkeit, das zu tun? Das ist meine Vorgehensweise, um mir keine Sorgen über das Ändern einer Datei zu machen, indem ich eine Pipeline verwende, die mit cat beginnt.perl -i -p -e 's/\n//' < infile > outfile
Wer braucht
sed
? Hier ist derbash
Weg:quelle
cat
:while read line; do echo -n "$line "; done < test.txt
. Kann nützlich sein, wenn eine Sub-Shell ein Problem darstellt.echo $(<file)
drückt alle Leerzeichen auf ein einziges Leerzeichen, nicht nur Zeilenumbrüche: Dies geht über das hinaus, was das OP verlangt.So ersetzen Sie alle Zeilenumbrüche mit awk durch Leerzeichen, ohne die gesamte Datei in den Speicher einzulesen:
Wenn Sie einen endgültigen Zeilenumbruch wünschen:
Sie können ein anderes Zeichen als Leerzeichen verwenden:
quelle
END{ print ""}
ist eine kürzere Alternative für eine nachfolgende Newline.ist der Befehl.
Einfach und leicht zu bedienen.
quelle
tr -d '\n'
wenn Sie kein Leerzeichen hinzufügen möchtenDrei Dinge.
tr
(odercat
usw.) wird absolut nicht benötigt. (GNU)sed
und (GNU)awk
können in Kombination 99,9% aller benötigten Textverarbeitungen ausführen.stream! = zeilenbasiert.
ed
ist ein zeilenbasierter Editor.sed
ist nicht. Siehe sed Vortrag , um weitere Informationen über den Unterschied. Die meisten Leute verwechselnsed
die Zeilenorientierung , da die Musterübereinstimmung für EINFACHE Übereinstimmungen standardmäßig nicht sehr gierig ist. Wenn Sie beispielsweise Muster suchen und durch ein oder zwei Zeichen ersetzen, wird sie standardmäßig nur bei der ersten Übereinstimmung ersetzt es findet (sofern im globalen Befehl nicht anders angegeben). Es würde nicht einmal einen globalen Befehl geben, wenn er eher zeilenbasiert als STREAM-basiert wäre, da nur Zeilen gleichzeitig ausgewertet würden. Versuche zu rennened
; Sie werden den Unterschied bemerken.ed
ist ziemlich nützlich, wenn Sie über bestimmte Zeilen iterieren möchten (z. B. in einer for-Schleife), aber meistens nursed
.Davon abgesehen,
funktioniert gut in GNU
sed
Version 4.2.1. Der obige Befehl ersetzt alle Zeilenumbrüche durch Leerzeichen. Es ist hässlich und etwas umständlich einzutippen, aber es funktioniert gut. Die{}
können weggelassen werden, da sie nur aus Gründen der Vernunft enthalten sind.quelle
sed
, um grundlegende Dinge zu tun, muss ich sagen, dass es mehr als nur darum geht, was man damit machen kann ,sed
sondern vielmehr darum , wie einfach es ist, zu verstehen, was los ist. Es fällt mir sehr schwer, damit zu arbeiten,sed
daher würde ich einen einfacheren Befehl bevorzugen, wenn ich ihn verwenden kann.t q
als bedingter Sprung dies funktioniert mit einem Muster wies/\n / /
(alle Linien zu verbinden , die mit einem Leerzeichen beginnen) , ohne die gesamte Datei in dem Speicher zu lesen. Praktisch beim Transformieren von Multi-Megabyte-Dateien.Die Antwort mit dem: ein Etikett ...
Wie kann ich eine neue Zeile (\ n) mit sed ersetzen?
... funktioniert nicht in freebsd 7.2 in der Kommandozeile:
Aber funktioniert es, wenn Sie das sed-Skript in eine Datei einfügen oder -e verwenden, um das sed-Skript zu "erstellen" ...
oder ...
Vielleicht ist das sed in OS X ähnlich.
quelle
Leicht verständliche Lösung
Ich hatte dieses Problem. Der Kicker war, dass ich die Lösung brauchte, um an BSDs (Mac OS X) und GNUs (Linux und Cygwin ) zu arbeiten
sed
undtr
:Ausgabe:
(hat nachgestellte Newline)
Es funktioniert unter Linux, OS X und BSD - auch ohne UTF-8- Unterstützung oder mit einem beschissenen Terminal.
Verwenden Sie
tr
diese Option, um die neue Zeile mit einem anderen Zeichen zu tauschen.NULL
(\000
oder\x00
) ist nett, weil es keine UTF-8-Unterstützung benötigt und wahrscheinlich nicht verwendet wird.Verwenden Sie
sed
, um die zu entsprechenNULL
Verwenden
tr
Sie diese Option, um zusätzliche Zeilenumbrüche bei Bedarf zurückzutauschenquelle
\000
wird allgemein alsNUL
(ein L) bezeichnet undNULL
wird im Allgemeinen verwendet, wenn von einem Nullzeiger gesprochen wird (in C / C ++).Sie können xargs verwenden :
oder
quelle
xargs < file.txt
Ich bin kein Experte, aber ich denke,
sed
Sie müssten zuerst die nächste Zeile in den Musterraum einfügen, indem Sie "N
" verwenden. Aus dem Abschnitt "Multiline Pattern Space" in "Advanced sed Commands" des Buches sed & awk (Dale Dougherty und Arnold Robbins; O'Reilly 1997; Seite 107 in der Vorschau ):Von
man sed
:Ich habe dies verwendet , um (mehrere) schlecht formatierte Protokolldateien zu durchsuchen, in denen die Suchzeichenfolge möglicherweise in einer "verwaisten" nächsten Zeile gefunden wird.
quelle
Ich habe einen hybriden Ansatz verwendet, um die Newline-Sache zu umgehen, indem ich tr verwendet habe, um Newlines durch Tabs zu ersetzen, und dann Tabs durch alles ersetzt habe, was ich will. In diesem Fall "
", da ich versuche, HTML-Unterbrechungen zu generieren.
quelle
Als Antwort auf die obige "tr" -Lösung unter Windows (wahrscheinlich unter Verwendung der Gnuwin32-Version von tr) wurde die vorgeschlagene Lösung vorgeschlagen:
funktionierte nicht für mich, es würde entweder einen Fehler machen oder das \ nw / '' aus irgendeinem Grund ersetzen.
Mit einer anderen Funktion von tr funktionierte die Option "Löschen" -d jedoch:
oder '\ r \ n' anstelle von '\ n'
quelle
tr "\n" " " < input
. Die Windows-Shell (cmd.exe) behandelt den Apostroph nicht als Anführungszeichen.tr "\n\r" " " < input.txt > output.txt
cat SourceFile.txt | tr --delete '\r\n' > OutputFile.txt
. Oder verwenden Sie anstelle von Gnuwin32 Gow (Gnu unter Windows), github.com/bmatzelle/gow/wikiKugelsichere Lösung. Binärdatensicher und POSIX-kompatibel, aber langsam.
POSIX sed erfordert eine Eingabe gemäß der POSIX-Textdatei und den POSIX- Zeilendefinitionen, sodass NULL-Bytes und zu lange Zeilen nicht zulässig sind und jede Zeile mit einer neuen Zeile (einschließlich der letzten Zeile) enden muss. Dies macht es schwierig, sed für die Verarbeitung beliebiger Eingabedaten zu verwenden.
Die folgende Lösung vermeidet sed und konvertiert stattdessen die eingegebenen Bytes in Oktalcodes und dann wieder in Bytes, fängt jedoch den Oktalcode 012 (Zeilenumbruch) ab und gibt stattdessen die Ersatzzeichenfolge aus. Soweit ich das beurteilen kann, ist die Lösung POSIX-kompatibel und sollte daher auf einer Vielzahl von Plattformen funktionieren.
POSIX-Referenzdokumentation: sh , Shell-Befehlssprache , od , tr , grep , read , [ , printf .
Beide
read
,[
undprintf
sind zumindest in Bash integriert, aber das wird von POSIX wahrscheinlich nicht garantiert. Auf einigen Plattformen kann es daher sein, dass jedes Eingabebyte einen oder mehrere neue Prozesse startet, was die Arbeit verlangsamt. Selbst in Bash erreicht diese Lösung nur etwa 50 kB / s, daher ist sie nicht für große Dateien geeignet.Getestet unter Ubuntu (Bash, Dash und Busybox), FreeBSD und OpenBSD.
quelle
In einigen Situationen können Sie möglicherweise
RS
zu einer anderen Zeichenfolge oder einem anderen Zeichen wechseln . Auf diese Weise ist \ n für sub / gsub verfügbar:Die Stärke von Shell-Skripten besteht darin, dass Sie es auf andere Weise tun können, wenn Sie nicht wissen, wie es auf eine Weise zu tun ist. Und oft müssen Sie mehr Dinge berücksichtigen, als eine komplexe Lösung für ein einfaches Problem zu finden.
In Bezug auf die Sache, dass gawk langsam ist ... und die Datei in den Speicher liest, weiß ich das nicht, aber für mich scheint gawk mit jeweils einer Zeile zu arbeiten und ist sehr sehr schnell (nicht so schnell wie einige der anderen , aber auch die Zeit zum Schreiben und Testen zählt).
Ich verarbeite MB und sogar GB Daten, und die einzige Grenze, die ich gefunden habe, ist die Zeilengröße.
quelle
Wenn Sie das Pech haben, sich mit Windows-Zeilenenden befassen zu müssen, müssen Sie das
\r
und das entfernen\n
quelle
[
durch einen Raum und\r
durch einen Raum und\n
durch einen Raum und]
durch einen Raum ersetzt.tr -d '\r\n' <file
würde alle\r
oder\n
Zeichen entfernen , aber das ist auch nicht das, was gefragt wird.tr -d '\r' <file
entfernt alle\r
Zeichen (unabhängig davon, ob sie benachbart sind\n
), was wahrscheinlich eher nützlich als möglicherweise für die Anforderungen des OP korrekt ist (vorausgesetzt, Sietr
verstehen diese Backslash-Notation).Sie können verwenden
xargs
- es wird\n
standardmäßig durch ein Leerzeichen ersetzt.Es würde jedoch Probleme geben, wenn Ihre Eingabe einen Fall von a aufweist
unterminated quote
, z. B. wenn die Anführungszeichen in einer bestimmten Zeile nicht übereinstimmen.quelle
Findet und ersetzt mit allow \ n
Wird
quelle
Warum habe ich mit keine einfache Lösung gefunden
awk
?printf
druckt jede Zeile ohne Zeilenumbrüche, wenn Sie die ursprünglichen Zeilen durch ein Leerzeichen oder ein anderes trennen möchten:quelle
echo "1\n2\n3" | awk '{printf $0}'
, das funktioniert bei mir. @ edi9999f
in printfUnter Mac OS X (mit FreeBSD sed):
quelle
So entfernen Sie leere Zeilen:
quelle
sed: 1: "s/^$//;t;p;": undefined label ';p;'
.Awk verwenden:
quelle
awk '{s = s sp $0; sp = " "} END {print s}'
. In meiner Antwort finden Sie jedoch eine Möglichkeit, awk zu verwenden, ohne die gesamte Datei in den Speicher einzulesen.Eine Lösung, die mir besonders gefällt, besteht darin, die gesamte Datei im Haltebereich anzuhängen und alle Zeilenumbrüche am Ende der Datei zu ersetzen:
Jemand sagte mir jedoch, dass der Haltebereich in einigen sed-Implementierungen begrenzt sein kann.
quelle
1h;2,$H;${x;s/\n/x/g;p}
Ersetzen Sie Zeilenumbrüche durch eine beliebige Zeichenfolge und ersetzen Sie auch die letzte Zeilenumbruch
Die reinen
tr
Lösungen können nur durch ein einzelnes Zeichen ersetzt werden, und die reinensed
Lösungen ersetzen nicht die letzte neue Zeile der Eingabe. Die folgende Lösung behebt diese Probleme und scheint für Binärdaten sicher zu sein (auch mit einem UTF-8-Gebietsschema):Ergebnis:
quelle
@
@
in der Eingabe ist OK. Es wird hin%a
und zurück entkommen . Die Lösung ist jedoch möglicherweise nicht vollständig POSIX-kompatibel (NULL-Bytes sind nicht zulässig, daher nicht gut für Binärdaten, und alle Zeilen müssen mit newline enden, damit dietr
Ausgabe nicht wirklich gültig ist).Es ist sed , das die neuen Zeilen nach "normaler" Substitution einführt. Zuerst wird das Zeichen für die neue Zeile gekürzt, dann wird es gemäß Ihren Anweisungen verarbeitet, und dann wird eine neue Zeile eingeführt.
Mit sed können Sie "das Ende" einer Zeile (nicht das Zeichen für neue Zeilen) ersetzen, nachdem Sie für jede Eingabezeile eine Zeichenfolge Ihrer Wahl zugeschnitten haben. aber sed ausgeben werden verschiedene Linien. Angenommen, Sie möchten das "Zeilenende" durch "===" ersetzen (allgemeiner als das Ersetzen durch ein einzelnes Leerzeichen):
Um das Zeichen für die neue Zeile durch die Zeichenfolge zu ersetzen, können Sie, wie bereits erwähnt, ineffizient tr verwenden , um die Zeichen für die neue Zeile durch ein "Sonderzeichen" zu ersetzen, und dann sed verwenden , um das Sonderzeichen durch die gewünschte Zeichenfolge zu ersetzen .
Zum Beispiel:
quelle
Sie können diese Methode auch verwenden
Erläuterung
Ablauf:
Wenn die erste Zeile von der Eingabe stammt, wird ein Austausch durchgeführt, sodass 1 in den Speicherbereich geht und \ n in den Musterbereich gelangt. Anschließend wird der Haltebereich an den Musterbereich angehängt. Anschließend wird der Musterbereich ersetzt und gelöscht.
Während des Austauschs der zweiten Zeile wird 2 in den Haltebereich und 1 in den Musterbereich verschoben. Anschließend wird der
G
Haltebereich in den Musterbereich eingefügt,h
das Muster in diesen kopiert und ersetzt und gelöscht. Dieser Vorgang wird fortgesetzt, bis eof erreicht ist, und dann das genaue Ergebnis gedruckt.quelle
echo 'Y' | sed 'x;G;1!h;s/\n/X/g;$!d'
zuXY
.Eine andere GNU-
sed
Methode, die fast der Antwort von Zsolt Botykai entspricht , jedoch densed
weniger häufig verwendeteny
( transliterierten ) Befehl verwendet, mit dem ein Byte Code (das nachfolgende) gespeichert wirdg
:Man würde hoffen,
y
dass es schneller läuft alss
(vielleicht mit einertr
Geschwindigkeit von 20x schneller), aber in GNU ist sed v4.2.2y
ungefähr 4% langsamer alss
.Tragbarere BSD-
sed
Version:quelle
y
ca. 15% schneller. In dieser Antwort finden Sie ein funktionierendes Beispiel.sed -e ':a' -e 'N;$!ba' -e 'y/\n/ /'
wäre der richtige Weg.