Ich habe mir diese Frage angesehen und mich dann gefragt, wie ich meine Antwortsed
implementieren könnte, die
nur
POSIX verwendet
ex
.
Der Trick ist, dass sed
ich zwar den Haltebereich mit dem Musterbereich vergleichen kann, um festzustellen, ob sie genau gleichwertig sind (mit
G;/^\(.*\)\n\1$/{do something}
), aber keine Möglichkeit kenne, einen solchen Test durchzuführen ex
.
Ich weiß, dass ich in Vim Y
die erste Zeile
ankeln und dann eingeben könnte, :2,$g/<C-r>0/d
um fast das zu tun, was ich spezifiziere - aber wenn die erste Zeile alles andere als sehr einfachen alphanumerischen Text enthält, wird dies in der Tat zu einem Zufall, da die Zeile als
Regex eingefügt wird , nicht nur eine Zeichenfolge zum Vergleich. (Und wenn die erste Zeile einen Schrägstrich enthält, wird der Rest der Zeile als Befehl interpretiert!)
Wenn ich also alle Zeilen löschen möchte myfile
, die mit der ersten Zeile identisch sind - aber nicht die erste Zeile löschen -, wie kann ich das verwenden ex
? Wie könnte ich das überhaupt tun vi
?
Gibt es eine POSIX-Möglichkeit, eine Zeile zu löschen, wenn sie genau mit einer anderen Zeile übereinstimmt?
Vielleicht so etwas wie diese imaginäre Syntax:
:2,$g/**lines equal to "0**/d
quelle
:execute '2,$g/\V' . escape(getline(1), '\') . '/d'
sed
als Filter von innen zu verwendenex
und meine gesamtesed
Antwort auf dem gesamten Puffer auszuführen ... was natürlich funktionieren würde (und im Gegensatz dazu tatsächlich portabel istsed -i
).<C-r>0
sehr gut. Ich bin mir nicht sicher, ob Sie nur mit Ex-Befehlen besser abschneiden können, da Sie Sonderzeichen schützen müssen. Ohne die POSIX-konforme Einschränkung würden Sie wahrscheinlich den sehr nomagischen Schalter verwenden\V
und dann den Backslash (da er auch\V
mit dieserescape()
Funktion seine besondere Bedeutung behält ) mit der Funktion schützen, deren zweites Argument eine Zeichenfolge ist, die alle Zeichen enthält, die Sie maskieren möchten .:execute '2,$g/\V' . escape(getline(1), '\/') . '/d'
Oder Sie könnten ein anderes Zeichen für das Mustertrennzeichen wie ein Semikolon verwenden. In diesem Fall müssten Sie keinen Schrägstrich im Muster schützen. Es würde so etwas wie geben::execute '2,$g;\V' . escape(getline(1), '\') . ';d'
sed
auch sehr gut. Mit Vim delegieren Sie häufig bestimmte spezielle Aufgaben an andere Programme undsed
sind wahrscheinlich ein gutes Beispiel dafür. Übrigens müssen Sie nichtsed
auf Ihrem gesamten Puffer laufen . Wenn Sie es nur für einen Teil des Puffers ausführen möchten, können Sie einen Bereich angeben. Wenn Sie beispielsweise nur die Zeilen zwischen 50 und 100 filtern möchten, können Sie Folgendes eingeben ::50,100!<your sed command>
.Antworten:
Vim
In Vim können Sie jedes Zeichen einschließlich Zeilenumbruch mit abgleichen
\_.
. Sie können dies verwenden, um ein Muster zu erstellen, das einer ganzen Linie, einer beliebigen Menge an Material und dann derselben Linie entspricht:Jetzt möchten Sie alle Zeilen in einer Datei löschen, die mit der ersten übereinstimmen, ohne die erste. Die Ersetzung zum Löschen der letzten Zeile, die mit der ersten übereinstimmt, lautet:
Mit können Sie
:global
sicherstellen, dass die Ersetzung so oft wiederholt wird, dass alle Zeilen gelöscht werden:POSIX ex
@saginaw zeigt in einem Kommentar zu Ihrer Frage eine bessere Möglichkeit, dies in Vim zu tun, aber wir können die obige Technik für POSIX ex anpassen.
Um dies auf POSIX-kompatible Weise zu tun, müssen Sie den mehrzeiligen Abgleich nicht zulassen, können jedoch weiterhin Rückreferenzen verwenden. Dies erfordert einige zusätzliche Arbeit:
Hier ist die Aufschlüsselung:
Wenn die aktuelle Zeile also ein Duplikat von Zeile 1 ist, enthält Register x
d
. Durch Ausführen wird die aktuelle Zeile gelöscht. Wenn es sich nicht um ein Duplikat handelt, enthält es einen vorangestellten Unsinn, bei"
dessen Ausführung ein No-Op angezeigt wird, da"
ein Kommentar gestartet wird. Ich weiß nicht, ob dies der beste Weg ist, dies zu erreichen. Es ist nur der erste, der mir in den Sinn kam!Es kommt einfach so vor, dass die erste Zeile nicht gelöscht werden kann, da der Kopiervorgang vorübergehend die Zeile 1 ändert. Wenn dies nicht der Fall gewesen wäre, könnten Sie dem stattdessen
:g
einen2,$
Bereich voranstellen .Getestet in Vim und Ex-Vi Version 4.0.
BEARBEITEN
Und eine einfachere Methode, bei der Sonderzeichen zum Erstellen eines Suchmusters (mit
'nomagic'
set) vermieden werden, erstellt einen:global
Befehl und führt ihn dann aus:Sie können dies jedoch nicht als Einzeiler tun, da Sie einen verschachtelten haben würden
:global
, was nicht erlaubt ist.quelle
Es scheint, dass der einzige POSIX-Weg, dies zu tun, die Verwendung eines externen Filters ist, wie z
sed
.Wenn Sie beispielsweise die 17. Zeile Ihrer Datei nur löschen möchten, wenn sie genau mit der 5. Zeile identisch ist, und sie ansonsten unverändert lassen, können Sie Folgendes tun:
(Sie könnten hier
sed
den gesamten Puffer ausführen , oder Sie könnten ihn nur in den Zeilen 5-17 ausführen, aber im ersten Fall führen Sie unnötige Filterung durch - keine große Sache - und im letzteren Fall müssten Sie den verwenden Nummern 1 und 13 in Ihremsed
Befehl anstelle von 5 und 17. Verwirrend.)Da
sed
nur ein einziger Vorwärtsdurchlauf ausgeführt wird, gibt es keine einfache Möglichkeit, den Rückwärtsgang durchzuführen und die 5. Zeile nur dann zu löschen, wenn sie mit der 17. Zeile identisch ist. Ich habe es eine Weile aus Neugier versucht ... es ist schwierig .Durchbruch - Sie können es so machen:
Dies ist eigentlich die allgemeinere Methode. Es kann ebenfalls verwendet werden, um das gleiche Ergebnis wie beim ersten Befehl zu erhalten (und die 17. Zeile nur zu löschen, wenn sie mit der 5. Zeile identisch ist).
Für breitere Verwendungszwecke wie das Löschen aller Zeilen der Datei, die mit Zeile 37 identisch sind, während Zeile 37 intakt bleibt, können Sie Folgendes tun:
Die Schlussfolgerung hier ist, zu überprüfen , ob zwei Linien identisch sind, das beste Werkzeug ist
sed
, nichtex
. Aber wie DevSolar in einem Kommentar angedeutet hat , ist dies kein Fehler vonvi
oderex
- sie sind für die Arbeit mit Unix-Tools ausgelegt. das ist eine große Stärke.quelle