UPDATE (siehe Ende der Frage)
Der Text "Hilfsprogramme suchen und ersetzen", den ich gesehen habe, scheint nur zeilenweise zu suchen ...
Gibt es ein Kommandozeilen - Tool , das kann lokalisieren (in einer Textdatei) einen Block von Linien, und ersetzen Sie es mit einem anderen Block von Linien.?
Beispiel: Enthält die Testdatei folgende exact group
Zeilen:
'Twas brillig, and the slithy toves
Did gyre and gimble in the wabe:
All mimsy were the borogoves,
And the mome raths outgrabe.
'Beware the Jabberwock, my son!
The jaws that bite, the claws that catch!
Beware the Jubjub bird, and shun
The frumious Bandersnatch!'
Ich möchte dies, damit ich mehrere Textzeilen in einer Datei ersetzen kann und weiß, dass ich nicht die falschen Zeilen überschreibe.
Ich würde "The Jabberwocky" (Lewis Carroll) niemals ersetzen, aber es ist ein neues Beispiel :)
UPDATE :
.. (sub-update) Mein folgender Kommentar über Gründe , wenn nicht ist sed verwendet nur im Kontext von; Schieben Sie kein Werkzeug zu weit über seine Konstruktionsabsicht hinaus (ich benutze sed ziemlich oft und halte es für von unschätzbarem Wert.)
Ich habe gerade eine interessante Webseite über sed gefunden und wann ich sie nicht benutzen soll.
Aufgrund all der sed- Antworten werde ich den Link posten. Er ist Teil der sed-FAQ zu sourceforge
Ich bin mir auch ziemlich sicher, dass es eine Möglichkeit diff
gibt, den Textblock zu lokalisieren (sobald er gefunden ist, ist der Ersatz ziemlich einfach; mit head
und tail
) ... 'diff' gibt alle erforderlichen Daten aus, aber ich habe noch nicht herausgefunden, wie man es filtert, ... (ich arbeite noch daran)
Ansatz 1: Ändern Sie die Zeilenumbrüche vorübergehend in etwas anderes
Das folgende Snippet tauscht Zeilenumbrüche gegen Pipes aus, führt den Austausch durch und tauscht Trennzeichen zurück. Das Dienstprogramm kann ersticken, wenn die Linie, die es sieht, extrem lang ist. Sie können ein beliebiges Zeichen zum Tauschen auswählen, solange es nicht in Ihrer Suchzeichenfolge enthalten ist.
Ansatz 2: Ändern Sie das Datensatztrennzeichen des Dienstprogramms
Awk und Perl unterstützen das Festlegen von zwei oder mehr Leerzeilen als Datensatztrennzeichen. Mit awk übergeben
-vRS=
(leereRS
Variable). Übergeben Sie mit Perl-000
(„Absatzmodus“) oder setzen Sie$,=""
. Dies ist hier jedoch nicht hilfreich, da Sie eine Suchzeichenfolge mit mehreren Absätzen haben.Awk und Perl unterstützen auch das Festlegen einer beliebigen Zeichenfolge als Datensatztrennzeichen. Setzen Sie
RS
oder$,
auf eine beliebige Zeichenfolge, die nicht in Ihrer Suchzeichenfolge enthalten ist.Ansatz 3: Arbeiten Sie an der gesamten Datei
Mit einigen Dienstprogrammen können Sie problemlos die gesamte Datei in den Speicher lesen und daran arbeiten.
Ansatz 4: Programm
Lesen Sie die Zeilen nacheinander. Beginnen Sie mit einem leeren Puffer. Wenn Sie die Zeile "'Twas" sehen und der Puffer leer ist, legen Sie ihn in den Puffer. Wenn Sie "Did gyre" sehen und sich eine Zeile im Puffer befindet, hängen Sie die aktuelle Zeile an den Puffer an und so weiter. Wenn Sie gerade die "Bandersnatch-Zeile" angehängt haben, geben Sie den Ersatztext aus. Wenn die aktuelle Zeile nicht in den Puffer aufgenommen wurde, drucken Sie den Pufferinhalt, drucken Sie die aktuelle Zeile und leeren Sie den Puffer.
psusi zeigt eine sed-Implementierung. In sed ist das Pufferkonzept integriert; Es heißt Hold Space. In awk oder perl verwenden Sie nur eine Variable (möglicherweise zwei, eine für den Pufferinhalt und eine für die Anzahl der Zeilen).
quelle
read -r
(ich habe gerade das -r heute entdeckt) der richtige Weg sein könnte ... Ich habe letzte Woche ein funktionierendes Skript geschrieben, das keinen regulären Ausdruck verwendet, aber ich wusste bereits, wo ich den Text finden kann ( über seine Zeilennummer).read -r
oder awk funktioniert möglicherweise zum Auffinden in einer unbekannten Datei.index
Funktion. Perl:index
Funktion,\Q…\E
Regexp-Escape.s/\Q$needle/$haystack/g
. Awk ist weniger einfach, aber machbar.Ich war mir sicher, dass es einen Weg geben musste, dies mit sed zu tun. Nach einigem googeln bin ich auf Folgendes gestoßen:
http://austinmatzko.com/2008/04/26/sed-multi-line-search-and-replace/
Aufgrund dessen schrieb ich am Ende:
sed -n '1h;1!H;${;g;s/foo\nbar/jar\nhead/g;p;}' < x
Welches hat den Inhalt von x richtig genommen:
Foo Bar
Und ausspucken:
Glas Kopf
quelle
Selbst wenn Sie hoary
sed
und nichtperl
mögen, finden Sie vielleicht immer noch eine Vorliebe für graue Vorlagenawk
. Diese Antwort scheint genau das zu sein, wonach Sie suchen. Ich reproduziere es hier. Angenommen , Sie haben drei Dateien und ersetzt werden sollenneedle
mitreplacement
inhaystack
:Dies beinhaltet keine regulären Ausdrücke und unterstützt Zeilenumbrüche. Es scheint mit ziemlich großen Dateien zu funktionieren. Es beinhaltet das Schlürfen der gesamten Datei in den Speicher, sodass es nicht mit Dateien beliebiger Größe funktioniert. Wenn Sie es eleganter wünschen, können Sie den gesamten Shebang in ein Bash-Skript einschließen oder in ein
awk
Skript umwandeln.quelle
[
,(
und falsche Ergebnisse auf$
,^
(die Daten nicht gefunden haben, obwohl es identisch war) ... Ich habe nicht weiter prüfen ... (aber der Befehl sieht „genau richtig“ :)gsub
scheint angemessener alssub
. Ich finde es ziemlich seltsam, dass kein einfaches mulitline nonregex-Dienstprogramm zum Suchen / Ersetzen aufgetaucht ist. Es scheint keinen einfachen Weg zu geben, der Suchnadel zu entkommen / sie zu zitieren ( zum Beispiel bei derperl
Verwendungquotemeta
).grep -F --fixed-strings
. Das bringt grep in eine ganz neue Kategorie (für mich) ... wieread -r
... wörtliche Interpretation ... Wenn ich das nursed
hätte, wäre alles sehr einfach ... (hat vielleichtawk
so etwas (?) .... und Übrigens ist der einfachste Teil des Ganzen das Ersetzen der Linien, ein einfacher Kopf (sobald die erste Zeilennummer identifiziert ist) | Katzenersatz | Schwanz der Rest (die Länge des entfernten Stücks ist bekannt) ... Also jetzt mitgrep -F -A{num}
bald genäht :) werden kannUPDATE : Loevborgs Python-Skript ist sicherlich die einfachste und beste Lösung (daran besteht kein Zweifel) und ich bin sehr zufrieden damit, aber ich möchte darauf hinweisen, dass das Bash-Skript, das ich vorgestellt habe (am Ende der Frage) ist bei weitem nicht so kompliziert wie es aussieht. Ich habe all die Debugging-Krätze herausgeschnitten, die ich zum Testen verwendet habe. Und hier ist es wieder ohne Überlastung (für jeden, der diese Seite besucht). Es ist im Grunde ein
sed
Einzeiler mit Hex-Conversions vor und nach:Um meinen Hut in den Ring zu werfen, habe ich eine "sed" -Lösung gefunden, die bei speziellen Regex-Zeichen keine Probleme verursacht , da nicht einmal eine verwendet wird! .. stattdessen funktioniert es auf Hexdumped-Versionen der Dateien ...
Ich denke , es ist zu „kopflastig“, aber es funktioniert, und wird offenbar nicht durch Größenbeschränkungen eingeschränkt .. GNU sed eine unbegrenzte hat Muster Puffergröße, und das ist , wo der Hexdumped Block von Suchlinien endet .. So In dieser Hinsicht ist es okay ...
Ich bin immer noch auf der Suche nach einer
diff
Lösung, weil sie in Bezug auf Leerraum flexibler sein wird (und ich würde erwarten; schneller) ... aber bis dahin ... ist es der berühmte Mr. Sed. :) :)Dieses Skript läuft vollständig wie es ist und wird vernünftigerweise kommentiert ...
Es sieht größer aus als es ist; Ich habe nur 7 Zeilen wesentlichen Codes.
Für einen semi-realistischen Test lädt es das Buch "Alice durch den Spiegel" von Project Gutenberg (363,1 KB) herunter ... und ersetzt das ursprüngliche Jabberwocky-Gedicht durch eine zeilenumgekehrte Version von sich selbst. (Interessanterweise ist es nicht viel anders rückwärts lesen :)
PS. Ich habe gerade festgestellt, dass eine Schwachstelle bei dieser Methode darin besteht, dass Ihr Original \ r \ n (0xODOA) als Zeilenumbruch verwendet und Ihr "übereinstimmender Text" mit \ n (0x0A) gespeichert wird Wasser ... ('diff' hat keine solchen Probleme) ...
quelle