Kennt jemand ein nicht zeilenbasiertes Tool zum "binären" Suchen / Ersetzen von Zeichenfolgen auf etwas speichereffiziente Weise? Siehe auch diese Frage .
Ich habe eine + 2GB-Textdatei, die ich ähnlich wie diese verarbeiten möchte:
sed -e 's/>\n/>/g'
Das heißt, ich möchte alle Zeilenumbrüche entfernen, die nach einem auftreten >
, aber nirgendwo anders, damit das ausschließt tr -d
.
Dieser Befehl (den ich aus der Antwort auf eine ähnliche Frage erhalten habe ) schlägt fehl mit couldn't re-allocate memory
:
sed --unbuffered ':a;N;$!ba;s/>\n/>/g'
Gibt es also andere Methoden, ohne auf C zurückzugreifen? Ich hasse Perl, bin aber bereit, in diesem Fall eine Ausnahme zu machen :-)
Ich weiß nicht genau, welches Zeichen in den Daten nicht vorkommt, daher \n
möchte ich es nach Möglichkeit vermeiden , es vorübergehend durch ein anderes Zeichen zu ersetzen .
Irgendwelche guten Ideen?
quelle
--unbuffered
?--unbuffered
Speicherplatzmangel$!
das?$!
ist. Ich gehe davon aus, dass dies eine Menge Speicher benötigt.sed
ist in diesem Fall nicht das richtige Werkzeug.Antworten:
Das ist in Perl wirklich trivial, du solltest es nicht hassen!
Erläuterung
-i
: Bearbeiten Sie die Datei an Ort und Stelle, und erstellen Sie eine Sicherungskopie des aufgerufenen Originalsfile.bak
. Wenn Sie keine Sicherung wünschen, verwenden Sieperl -i -pe
stattdessen einfach .-pe
: Lies die Eingabedatei Zeile für Zeile und drucke jede Zeile nach dem Anwenden des Skripts aus-e
.s/>\n/>/
: die Substitution, genau wiesed
.Und hier ist ein
awk
Ansatz:quelle
awk '{ORS=/>$/?"":"\n"}1'
':a;N;$!ba;s/>\n/>/g'
in Ihrer Frage erwähnt haben, haben Sie auf Ihr Recht verzichtet, sich über die Lesbarkeit zu beschweren! : Pfoo ? bar : baz
Konstrukt gespielt, konnte es aber nicht zum Laufen bringen.Eine
perl
Lösung:Erklärung
s///
wird für die Zeichenfolgensubstitution verwendet.(?<=>)
ist ein Lookbehind-Muster.\n
stimmt mit newline überein.Das ganze Muster bedeutet, dass alle Zeilenumbrüche entfernt werden, die
>
davor stehen.quelle
s/>\n/>/
?s/>\K\n//
würde auch funktionierenWie wäre es damit:
Bei GNU sed können Sie auch versuchen, die Option
-u
(--unbuffered
) gemäß der Frage hinzuzufügen . GNU sed ist damit auch als einfacher Einzeiler zufrieden:quelle
\n
wenn die Datei endet>\n
, aber das ist wahrscheinlich sowieso vorzuziehen.}
in einem separaten Ausdruck stehen? Funktioniert dies nicht als mehrzeiliger Ausdruck?b loop\n}
oder-e 'b loop' -e '}'
aber nicht alsb loop;}
und schon gar nicht alsb loop}
weil}
und;
ist in Labelnamen gültig (obwohl niemand, der es richtig versteht, es verwenden würde. Und das bedeutet, dass GNU sed nicht POSIX-konform ist), und der}
Befehl muss getrennt werden aus demb
Befehl.sed
ist mit all dem zufrieden, auch mit--posix
! Der Standard hat auch die folgenden Angaben für Klammerausdrücke -The list of sed functions shall be surrounded by braces and separated by <newline>s
. Bedeutet dies nicht, dass Semikolons nur außerhalb von geschweiften Klammern verwendet werden sollten?>
. Das Original hatte nie eines, darauf wies Stéphane hin.Sie sollten in der Lage sein,
sed
denN
Befehl zu verwenden, aber der Trick besteht darin, bei jedem Hinzufügen einer weiteren Zeile eine Zeile aus dem Musterbereich zu löschen (sodass der Musterbereich immer nur zwei aufeinanderfolgende Zeilen enthält, anstatt zu versuchen, das Ganze einzulesen Datei) - versuchenEDIT: nach dem erneuten Lesen von Peteris Krumins ' Famous Sed One-Liners Explained glaube ich, dass eine bessere
sed
Lösung wäreDies hängt die folgende Zeile nur an, wenn sie bereits
>
am Ende übereinstimmt, und sollte eine bedingte Schleife ausführen , um den Fall aufeinanderfolgender übereinstimmender Zeilen zu behandeln (dies ist Krumins 39. Fügen Sie eine Zeile an die nächste an, wenn sie mit einem Backslash endet "\" genau mit Ausnahme der Ersetzung von>
for\
als Verknüpfungszeichen und der Tatsache, dass das Verknüpfungszeichen in der Ausgabe beibehalten wird).quelle
>
(das ist auch GNU-spezifisch)sed
bietet keine Möglichkeit, eine Ausgabe ohne eine letzte neue Zeile auszugeben. Ihre Vorgehensweise mit der Verwendung vonN
funktioniert grundsätzlich, speichert jedoch unvollständige Zeilen im Speicher und kann daher fehlschlagen, wenn die Zeilen zu lang werden (sed-Implentationen sind normalerweise nicht für extrem lange Zeilen ausgelegt).Sie können stattdessen awk verwenden.
Ein alternativer Ansatz besteht darin
tr
, das Newline-Zeichen durch ein "langweiliges", häufig vorkommendes Zeichen zu ersetzen. Hier könnte Platz funktionieren - wählen Sie ein Zeichen, das in jeder Zeile oder zumindest in einem großen Teil der Zeilen in Ihren Daten vorkommt.quelle
sed
geht nicht ohne einen 2,5-Gigabyte-Puffer.tr
Ansatz - mikeserv, Sie haben einen anderen (gültigen, aber weniger generischen) Ansatz gepostet, der zufällig auch verwendet wirdtr
.was ist mit ed?
(via http://wiki.bash-hackers.org/howto/edit-ed )
quelle
Am Ende habe ich gsar verwendet, wie in der folgenden Antwort beschrieben :
quelle
Es gibt viele Möglichkeiten, dies zu tun, und die meisten hier sind wirklich gut, aber ich denke, dies ist mein Favorit:
Oder auch:
quelle
*
. So wie es jetzt ist, werden alle leeren Zeilen gelöscht, die auf eine Zeile folgen, die mit einem endet>
. … Hmm. Wenn ich auf die Frage zurückblicke, sehe ich, dass sie etwas mehrdeutig ist. Die Frage lautet: "Ich möchte alle Zeilenumbrüche entfernen, die nach einem>
, ... auftreten." Ich interpretiere das so, dass>\n\n\n\n\nfoo
dies in geändert werden sollte\n\n\n\nfoo
, aber ich nehme an , dass diesfoo
möglicherweise die gewünschte Ausgabe ist.printf '>\n>\n\n>>\n>\n>>>\n>\nf\n\nff\n>\n' | tr '>\n' '\n>' | sed 's/^>*//;H;/./!d;x;y/\n>/>\n/'
- Das ergibt>>>>>>>>>>f\n\nff\n\n
für mich die erste Antwort. Ich bin allerdings neugierig, was Sie tun, um es zu brechen, weil ich es reparieren möchte. Was den zweiten Punkt betrifft, stimme ich nicht zu, dass er mehrdeutig ist. Das OP fordert nicht auf, alle>
vor einer\n
E-Line stehenden E-Lines zu entfernen, sondern alle\n
E-Lines nach a>
.>\n\n\n\n\n
nur die erste Zeile nach a steht>
; Alle anderen folgen anderen Zeilenumbrüchen. Beachten Sie, dass der Vorschlag des OP "das ist, was ich will, wenn es nur funktioniert" warsed -e 's/>\n/>/g'
, nichtsed -e 's/>\n*/>/g'
.s/>\n/>/
auf>\n\n\n\n\n
wäre noch etwas , dasss/>\n/>/
Would bearbeiten.