Ich habe kürzlich eine Frage gestellt, wie das Zeilenumbruchzeichen entfernt werden kann, wenn es nach einem anderen bestimmten Zeichen auftritt.
Unix-Textverarbeitungswerkzeuge sind sehr leistungsfähig, aber fast alle verarbeiten Textzeilen. Dies ist meistens dann in Ordnung, wenn die Eingabe in den verfügbaren Speicher passt.
Aber was soll ich tun, wenn ich eine Textsequenz in einer riesigen Datei ersetzen möchte, die keine Zeilenumbrüche enthält?
Zum Beispiel ersetzen <foobar>
mit \n<foobar>
ohne die Eingabe Zeile für Zeile zu lesen? (da es nur eine Zeile gibt und sie 2,5 GB Zeichen lang ist).
text-processing
MattBianco
quelle
quelle
perl
oderpython
?gsar
( home.online.no/~tjaberg ) gefunden, was ich versuchen werde.Antworten:
Das erste, was mir bei solchen Problemen einfällt, ist das Ändern des Datensatztrennzeichens. In den meisten Tools ist dies
\n
standardmäßig eingestellt, dies kann jedoch geändert werden. Beispielsweise:Perl
Erläuterung
-0
: Hiermit wird das Trennzeichen für den Eingabesatz auf ein Zeichen gesetzt, dessen hexadezimaler Wert angegeben wird . In diesem Fall setze ich es auf>
dessen Hex-Wert3E
. Das allgemeine Format ist-0xHEX_VALUE
. Dies ist nur ein Trick, um die Linie in überschaubare Teile zu unterteilen.-pe
: Gibt jede Eingabezeile aus, nachdem das Skript von angewendet wurde-e
.s/<foobar>/\n$&/
: eine einfache Ersetzung. In$&
diesem Fall stimmt das mit dem überein<foobar>
.awk
Erläuterung
RS="<"
: Setzen Sie das Trennzeichen für den Eingabesatz auf>
.gsub(/foobar>/,"\n<foobar>")
: Ersetze alle Fälle vonfoobar>
mit\n<foobar>
. Beachten Sie, dass daRS
gesetzt wurde , um<
alle<
von der Eingabedatei entfernt werden (das ist , wieawk
funktioniert) , so dass wir übereinstimmen müssenfoobar>
(ohne<
) und ersetzen\n<foobar>
.printf "%s",$0
: druckt die aktuelle "Zeile" nach der Ersetzung.$0
Ist der aktuelle Rekord inawk
so wird es halten, was vor dem<
.Ich habe diese mit einer einzeiligen 2,3-GB-Datei getestet, die mit den folgenden Befehlen erstellt wurde:
Sowohl die
awk
als auch dieperl
verwendete vernachlässigbare Menge an Speicher.quelle
Tie::File
perldoc.perl.org/Tie/File.html . Ich denke, es ist die beste FunktionPerl
beim Umgang mit großen Dateien.Tie::File
seitdem ein Kernmodul istv5.7.3
.gsar (allgemeines Suchen und Ersetzen) ist ein sehr nützliches Werkzeug für genau diesen Zweck.
Bei den meisten Antworten auf diese Frage werden auf Datensätzen basierende Tools und verschiedene Tricks verwendet, um sie an das Problem anzupassen, z.
In vielen Fällen ist dies sehr gut und sogar lesbar. Ich mag Probleme , die leicht sein können / effizient mit überall erhältlichen Tool gelöst wie
awk
,tr
,sed
und dem Bourne - Shell.Das Durchführen einer binären Suche und Ersetzung in einer beliebig großen Datei mit zufälligem Inhalt passt nicht sehr gut zu diesen Standard-Unix-Tools.
Einige von Ihnen denken vielleicht, dass dies ein Betrug ist, aber ich sehe nicht, wie falsch es sein kann, das richtige Werkzeug für den Job zu verwenden. In diesem Fall handelt es sich um ein C-Programm
gsar
, das unter der GPL v2 lizenziert ist. Daher wundert es mich sehr, dass es weder in gentoo , redhat noch in ubuntu ein Paket für dieses sehr nützliche Tool gibt .gsar
verwendet eine binäre Variante des Boyer-Moore-Suchalgorithmus .Die Verwendung ist unkompliziert:
Dabei
-F
bedeutet "Filter" -Modus, dh Lesen,stdin
Schreibenstdout
. Es gibt auch Methoden zum Bearbeiten von Dateien.-s
Gibt die Suchzeichenfolge und-r
die Ersetzung an. Mit der Doppelpunktnotation können beliebige Bytewerte angegeben werden.Groß- und Kleinschreibung wird nicht berücksichtigt (
-i
), reguläre Ausdrücke werden jedoch nicht unterstützt, da der Algorithmus die Länge der Suchzeichenfolge verwendet, um die Suche zu optimieren.Das Tool kann auch nur zum Suchen verwendet werden
grep
.gsar -b
gibt die Byte-Offsets der übereinstimmendengsar -l
Suchzeichenfolge aus und gibt den Dateinamen und die Anzahl der Übereinstimmungen aus, wenn überhaupt, ähnlich wie bei der Kombinationgrep -l
mitwc
.Das Tool wurde von Tormod Tjaberg (Initiale) und Hans Peter Verne (Verbesserungen) geschrieben.
quelle
gsar
.In dem engen Fall, in dem Ziel- und Ersatzzeichenfolgen dieselbe Länge haben, kann die Speicherzuordnung Abhilfe schaffen . Dies ist besonders nützlich, wenn der Austausch vor Ort durchgeführt werden muss. Sie ordnen eine Datei im Grunde genommen dem virtuellen Speicher eines Prozesses zu, und der Adressraum für die 64-Bit-Adressierung ist riesig. Beachten Sie, dass die Datei nicht unbedingt auf einmal im physischen Speicher abgelegt wird , sodass Dateien verarbeitet werden können, die mehrmals so groß sind wie der auf dem Computer verfügbare physische Speicher.
Hier ist ein Python - Beispiel , das ersetzt
foobar
mitXXXXXX
quelle
Dafür gibt es viele Tools:
dd
ist das, was Sie verwenden möchten, wenn Sie eine Datei blockieren möchten - zuverlässig nur eine bestimmte Anzahl von Bytes nur eine bestimmte Anzahl von Malen lesen. Es handhabt portabel das Blockieren und Entsperren von Dateistreams:tr -dc '[:graph:]' </dev/urandom | dd bs=32 count=1 cbs=8 conv=unblock,sync 2>/dev/null
UI(#Q5\e BKX2?A:Z RAxGm:qv t!;/v!)N
Ich benutze
tr
es auch oben, weil es das Konvertieren eines beliebigen ASCII-Bytes in ein beliebiges anderes (oder in diesem Fall das Löschen eines beliebigen ASCII-Bytes, das kein druckbares Zeichen ohne Leerzeichen ist) handhaben kann. Das habe ich heute Morgen bei der Beantwortung Ihrer anderen Frage verwendet, als ich Folgendes getan habe:Es gibt viele ähnliche . Diese Liste sollte eine Teilmenge mit dem kleinsten gemeinsamen Nenner enthalten, mit der Sie möglicherweise vertraut sind.
Aber wenn ich eine Textverarbeitung mit 2,5 GB Binärdatei durchführen würde, könnte ich damit beginnen
od
. Es kann Ihnen einoctal dump
oder mehrere andere Formate geben. Sie können alle Arten von Optionen angeben - aber ich mache nur ein Byte pro Zeile in einem\C
maskierten Format:Die Daten, die Sie von erhalten
od
, werden regelmäßig in einem von Ihnen festgelegten Intervall abgerufen - wie ich unten zeige. Aber zuerst - hier ist eine Antwort auf Ihre Frage:Das etwas über Delimitis auf
\n
ewlines,\0
nulls,\t
abs und<spaces>
gleichzeitig die Erhaltung der\C
Escape - Sequenzen für das Trennzeichen. Beachten Sie dieH
undx
verwendeten Funktionen - jedes Mal ,sed
trifft auf einen Begrenzer es , den Inhalt seiner Speicherpuffer auslagert. Auf diese Weisesed
bleiben nur so viele Informationen erhalten, wie für eine zuverlässige Abgrenzung der Datei erforderlich sind, und es kommt nicht zu Pufferüberläufen. Solange es das tut,sed
wird es seine Eingaben weiterverarbeiten undod
weiter zur Verfügung stellen, bis es auf sie trifftEOF
.Die Ausgabe sieht wie folgt aus:
Also wenn ich will
foobar
:Wenn Sie nun die Escape-Zeichen verwenden möchten,
C
ist dies ziemlich einfach - dased
bereits\\
alle Backslash-printf
Zeichen für einzelne Eingaben durch einen doppelten Backslash maskiert wurden , hat die Ausführung vonxargs
keine Probleme, die Ausgabe gemäß Ihrer Spezifikation zu erstellen . Es werden jedochxargs
Shell-Anführungszeichen verwendet, sodass Sie es erneut in doppelte Anführungszeichen setzen müssen:Das hätte genauso einfach in einer Shell-Variablen gespeichert und später auf identische Weise ausgegeben werden können. Der letzte
sed
fügt einen\
Backslash vor jedem Zeichen in die Eingabe ein, und das ist alles.Und so sieht alles aus, bevor es jemals in den
sed
Griff kommt:quelle
Awk bearbeitet aufeinanderfolgende Datensätze. Es kann ein beliebiges Zeichen als Datensatztrennzeichen verwendet werden (mit Ausnahme des Null-Bytes bei vielen Implementierungen). Einige Implementierungen unterstützen beliebige reguläre Ausdrücke (die nicht mit der leeren Zeichenfolge übereinstimmen) als Datensatztrennzeichen. Dies kann jedoch unhandlich sein, da das Datensatztrennzeichen am Ende jedes Datensatzes abgeschnitten wird, bevor es gespeichert wird
$0
(GNU awk setzt die VariableRT
auf das Datensatztrennzeichen) das wurde vom Ende des aktuellen Datensatzes entfernt). Beachten Sie, dassprint
die Ausgabe mit dem AusgabesatztrennzeichenORS
endet, das standardmäßig ein Zeilenumbruch ist und unabhängig vom Eingabesatztrennzeichen festgelegt wirdRS
.Sie können effektiv einen anderen Charakter als Datensatztrennzeichen für andere Tools (wählen
sort
,sed
...) durch Zeilenumbrüche mit diesem Zeichen mit Swappingtr
.Viele GNU-Textdienstprogramme unterstützen die Verwendung eines Null-Bytes anstelle einer Newline als Trennzeichen.
quelle