Ihr Problem mit Vim ist, dass du nicht verstehst, was ich meine. vi .
Sie erwähnen das Schneiden mit yy
und beschweren sich, dass Sie fast nie ganze Zeilen abschneiden wollen. In der Tat wollen Programmierer bei der Bearbeitung von Quellcode sehr oft ganze Zeilen, Zeilenbereiche und Codeblöcke bearbeiten. Wie auch immer, yy
ist nur eine von vielen Möglichkeiten, Text in den anonymen Kopierpuffer (oder "Register", wie es in vi ).
Das "Zen" der vi ist, dass du eine Sprache sprichst. Die anfängliche y
ist ein Verb. Die Aussage yy
ist ein Synonym für y_
. Die y
wird verdoppelt, um die Eingabe zu erleichtern, da es sich um einen sehr häufigen Vorgang handelt.
Dies kann auch wie folgt ausgedrückt werden dd
P
(Löschen der aktuellen Zeile und Einfügen einer Kopie an dieser Stelle; als Nebeneffekt bleibt eine Kopie im anonymen Register zurück). Die Website y
y d
"Verben" nehmen jede Bewegung als "Subjekt". So yW
ist "von hier (dem Cursor) bis zum Ende des aktuellen/nächsten (großen) Wortes ziehen" und y'a
ist "von hier bis zu der Zeile, die die Marke mit dem Namen ' a '."
Wenn Sie nur die grundlegenden Bewegungen des Cursors nach oben, unten, links und rechts verstehen, dann vi wird für Sie nicht produktiver sein als eine Kopie von "notepad". (Okay, Sie haben immer noch die Syntaxhervorhebung und die Möglichkeit, Dateien zu bearbeiten, die größer sind als die läppischen ~45KB oder so; aber arbeiten Sie mit mir hier).
vi hat 26 "Marken" und 26 "Register". Eine Markierung wird an eine beliebige Cursorposition gesetzt, indem die m
Befehl. Jedes Zeichen wird durch einen einzelnen Kleinbuchstaben gekennzeichnet. Also ma
setzt die ' a Markierung für den aktuellen Standort, und mz
setzt die ' z ' Zeichen. Sie können zu der Zeile, die eine Markierung enthält, mit der Taste '
(einfaches Anführungszeichen). Also 'a
springt an den Anfang der Zeile, die den ' a ' Zeichen. Sie können die genaue Position jeder Markierung mit der Taste `
(Anführungszeichen). Also `z
direkt an die genaue Stelle des ' z ' mark.
Da es sich um "Bewegungen" handelt, können sie auch als Themen für andere "Aussagen" verwendet werden.
Eine Möglichkeit, eine beliebige Auswahl von Text auszuschneiden, wäre also, eine Markierung zu setzen (ich verwende normalerweise ' a ' als meine "erste" Marke, ' z ' als mein nächstes Ziel, ' b ' als weitere, und ' e (Ich kann mich nicht erinnern, dass ich in den 15 Jahren, in denen ich das Programm benutze, jemals mehr als vier Zeichen interaktiv verwendet habe. vi Man schafft sich seine eigenen Konventionen für die Verwendung von Markierungen und Registern durch Makros, die den eigenen interaktiven Kontext nicht stören). Dann gehen wir an das andere Ende unseres gewünschten Textes; wir können an beiden Enden beginnen, das spielt keine Rolle. Dann können wir einfach verwenden d`a
zu schneiden oder y`a
zu kopieren. Der gesamte Vorgang hat also einen Overhead von 5 Tastenanschlägen (sechs, wenn wir im "Einfügemodus" beginnen und Esc out Befehlsmodus). Nach dem Ausschneiden oder Kopieren ist das Einfügen einer Kopie nur noch ein Tastendruck: p
.
Ich sage, dass dies eine Möglichkeit ist, Text auszuschneiden oder zu kopieren. Es ist aber nur eine von vielen. Häufig können wir den Textbereich knapper beschreiben, ohne den Cursor zu bewegen und eine Markierung zu setzen. Wenn ich mich zum Beispiel in einem Textabsatz befinde, kann ich Folgendes verwenden {
y }
Bewegungen an den Anfang bzw. das Ende des Absatzes. Um also einen Textabsatz zu verschieben, schneide ich ihn mit {
d}
(3 Tastenanschläge). (Wenn ich mich bereits in der ersten oder letzten Zeile des Absatzes befinde, kann ich einfach mit d}
ou d{
beziehungsweise.
Der Begriff "Absatz" gibt etwas vor, das normalerweise intuitiv sinnvoll ist. Daher funktioniert er oft sowohl für Code als auch für Prosa.
Häufig kennen wir ein Muster (regulärer Ausdruck), das das eine oder andere Ende des Textes, an dem wir interessiert sind, markiert. Vorwärts- oder Rückwärtssuchen sind Bewegungen in vi . Sie können also auch als "Subjekte" in unseren "Aussagen" verwendet werden. Ich kann also verwenden d/foo
um von der aktuellen Zeile bis zur nächsten Zeile, die die Zeichenkette "foo" enthält, zu schneiden und y?bar
um von der aktuellen Zeile zur letzten (vorherigen) Zeile zu kopieren, die "bar" enthält. Wenn ich keine ganzen Zeilen will, kann ich immer noch die Suchbewegungen (als eigene Anweisungen) verwenden, meine Markierung(en) weglassen und die `x
Befehle wie zuvor beschrieben.
Zusätzlich zu "Verben" und "Subjekten" vi hat auch "Objekte" (im grammatikalischen Sinne des Wortes). Bis jetzt habe ich nur die Verwendung des anonymen Registers beschrieben. Ich kann jedoch jedes der 26 "benannten" Register verwenden, indem ich Voranstellen von die "Objekt"-Referenz mit "
(der Modifikator für Anführungszeichen). Wenn ich also verwende "add
Ich schneide die aktuelle Zeile in die ' a ' registrieren und wenn ich "by/foo
dann füge ich eine Kopie des Textes von hier bis zur nächsten Zeile, die "foo" enthält, in die ' b ' registrieren. Um aus einem Register einzufügen, stelle ich dem Einfügen einfach die gleiche Modifizierungssequenz voran: "ap
fügt eine Kopie des Dokuments ' a den Inhalt des Registers in den Text nach dem Cursor und "bP
fügt eine Kopie von ' b ' vor die aktuelle Zeile zu setzen.
Dieser Begriff der "Präfixe" fügt auch die Analoga der grammatikalischen "Adjektive" und "Adverbien" zu unserer Textmanipulations-"Sprache" hinzu. Die meisten Befehle (Verben) und Bewegungen (Verben oder Objekte, je nach Kontext) können auch numerische Präfixe annehmen. So 3J
bedeutet "die nächsten drei Zeilen verbinden" und d5}
bedeutet "von der aktuellen Zeile bis zum Ende des fünften Absatzes von hier an löschen".
Dies ist alles Mittelstufe vi . Nichts davon ist Vim spezifisch und es gibt weitaus fortgeschrittenere Tricks in vi wenn Sie bereit sind, sie zu lernen. Wenn Sie nur diese Zwischenkonzepte beherrschen, werden Sie wahrscheinlich feststellen, dass Sie nur selten Makros schreiben müssen, da die Textmanipulationssprache prägnant und ausdrucksstark genug ist, um die meisten Dinge einfach mit der "Muttersprache" des Editors zu erledigen.
Eine Auswahl fortgeschrittener Tricks:
Es gibt eine Reihe von :
Befehle, vor allem der :% s/foo/bar/g
globale Substitutionstechnik. (Das ist nicht fortschrittlich, aber andere :
Befehle sein können). Das Ganze :
Reihe von Befehlen wurde historisch vererbt von vi die früheren Inkarnationen der ed (Zeileneditor) und später die ex (erweiterter Zeileneditor) Dienstprogramme. In der Tat vi ist so benannt, weil es die visuelle Schnittstelle zu ex .
:
Befehle arbeiten normalerweise über Textzeilen. ed y ex wurden in einer Zeit geschrieben, in der Terminalbildschirme unüblich waren und viele Terminals "Fernschreibgeräte" (TTY) waren. Daher war es üblich, mit gedruckten Kopien des Textes zu arbeiten und Befehle über eine extrem knappe Schnittstelle zu verwenden (die üblichen Verbindungsgeschwindigkeiten betrugen 110 Baud oder, grob gesagt, 11 Zeichen pro Sekunde - was langsamer ist als eine schnelle Schreibkraft; Verzögerungen waren bei interaktiven Sitzungen mit mehreren Benutzern üblich; außerdem gab es oft eine Motivation, Papier zu sparen).
Daher ist die Syntax der meisten :
Befehle umfassen eine Adresse oder einen Adressbereich (Zeilennummer), gefolgt von einem Befehl. Natürlich kann man auch wörtliche Zeilennummern verwenden: :127,215 s/foo/bar
um das erste Vorkommen von "foo" in "bar" in jeder Zeile zwischen 127 und 215 zu ändern. Man könnte auch einige Abkürzungen verwenden, wie zum Beispiel .
ou $
für die aktuelle bzw. letzte Zeile. Man könnte auch relative Präfixe verwenden +
y -
um sich auf Offsets nach bzw. vor der aktuellen Zeile zu beziehen. Also: :.,$j
bedeutet "von der aktuellen Zeile bis zur letzten Zeile alle in einer Zeile zusammenfassen". :%
ist gleichbedeutend mit :1,$
(alle Zeilen).
Le site :... g
y :... v
Befehle bedürfen einer gewissen Erklärung, da sie unglaublich mächtig sind. :... g
ist ein Präfix für die "globale" Anwendung eines nachfolgenden Befehls auf alle Zeilen, die einem Muster (regulärer Ausdruck) entsprechen, während :... v
wendet einen solchen Befehl auf alle Zeilen an, die NICHT mit dem angegebenen Muster ("v" aus "conVerse") übereinstimmen. Wie bei anderen ex Befehlen können Adressierungs-/Bereichsreferenzen vorangestellt werden. So :.,+21g/foo/d
bedeutet "lösche alle Zeilen, die die Zeichenfolge "foo" enthalten, von der aktuellen bis zu den nächsten 21 Zeilen", während :.,$v/bar/d
bedeutet: "Lösche von hier bis zum Ende der Datei alle Zeilen, die NICHT die Zeichenfolge "bar" enthalten.
Es ist interessant, dass der gängige Unix-Befehl grep wurde eigentlich durch dieses Buch inspiriert ex Befehl (und ist nach der Art und Weise benannt, wie er dokumentiert wurde). Der ex commande :g/re/p
(grep) wurde dokumentiert, wie man Zeilen, die einen "regulären Ausdruck" (re) enthalten, "global" "drucken" kann. Wenn ed y ex verwendet wurden, die :p
war einer der ersten Befehle, die man lernte, und oft der erste, der beim Bearbeiten einer Datei verwendet wurde. Mit diesem Befehl wurde der aktuelle Inhalt gedruckt (normalerweise immer nur eine Seite auf einmal mit :.,+25p
oder ähnliches).
Beachten Sie, dass :% g/.../d
oder (sein reVerse/conVerse-Gegenstück: :% v/.../d
sind die häufigsten Verwendungsmuster. Es gibt jedoch noch eine Reihe anderer ex
Befehle, die man sich merken sollte:
Wir können verwenden m
um Linien zu verschieben, und j
um Linien zu verbinden. Wenn Sie z.B. eine Liste haben und alles, was auf ein Muster passt (oder umgekehrt NICHT passt) trennen wollen, ohne es zu löschen, dann können Sie etwas verwenden wie: :% g/foo/m$
... und alle "foo"-Zeilen sind an das Ende der Datei verschoben worden. (Beachten Sie den anderen Tipp, das Ende der Datei als Leerzeichen zu verwenden). Dadurch wird die relative Reihenfolge aller "foo"-Zeilen beibehalten, während sie aus dem Rest der Liste extrahiert wurden. (Dies wäre gleichbedeutend mit etwas wie: 1G!GGmap!Ggrep foo<ENTER>1G:1,'a g/foo'/d
(Kopieren der Datei in ihren eigenen Schwanz, Filtern des Schwanzes durch grep
und löschen Sie alles, was im Kopf ist).
Um Zeilen zu verbinden, kann ich normalerweise ein Muster für alle Zeilen finden, die mit ihrem Vorgänger verbunden werden müssen (z. B. alle Zeilen, die mit "^ " und nicht mit "^ * " in einer Aufzählung beginnen). In diesem Fall würde ich verwenden: :% g/^ /-1j
(gehen Sie für jede übereinstimmende Zeile eine Zeile nach oben und verbinden Sie sie). (BTW: bei Aufzählungslisten funktioniert die Suche nach den Aufzählungszeilen und das Verbinden mit der nächsten aus mehreren Gründen nicht ... es kann eine Aufzählungszeile mit einer anderen verbinden, und es wird keine Aufzählungszeile mit einer anderen verbinden. alle seiner Fortsetzungen; es wird nur paarweise auf die Übereinstimmungen funktionieren).
Fast überflüssig zu erwähnen, dass Sie unseren alten Freund s
(Ersatz) mit dem g
y v
(global/umgekehrt-global) Befehle. Normalerweise ist dies nicht erforderlich. Denken Sie jedoch an einen Fall, in dem Sie eine Ersetzung nur für Zeilen durchführen wollen, die einem anderen Muster entsprechen. Oft können Sie ein kompliziertes Muster mit Captures verwenden und Rückverweise einsetzen, um die Teile der Zeilen zu erhalten, die Sie NICHT ändern wollen. Oft wird es jedoch einfacher sein, die Übereinstimmung von der Ersetzung zu trennen: :% g/foo/s/bar/zzz/g
-- für jede Zeile, die "foo" enthält, alle "bar" durch "zzz" ersetzen. (Etwas wie :% s/\(.*foo.*\)bar\(.*\)/\1zzz\2/g
würde nur für die Fälle funktionieren, in denen "bar" von "foo" in derselben Zeile VORANGESTELLT wurde; es ist schon unhandlich genug und müsste noch weiter verfälscht werden, um alle Fälle zu erfassen, in denen "bar" vor "foo" stand)
Der Punkt ist, dass es mehr gibt als nur p
, s
und d
Zeilen im ex
Befehlssatz.
Le site :
Adressen können sich auch auf Marken beziehen. So können Sie verwenden: :'a,'bg/foo/j
um jede Zeile, die die Zeichenkette foo enthält, mit der nachfolgenden Zeile zu verbinden, wenn sie zwischen den Zeilen zwischen den ' a ' und ' b ' Noten. (Ja, alle vorhergehenden ex
Befehlsbeispiele können durch Voranstellen dieser Art von Adressierungsausdrücken auf Teilmengen der Dateizeilen beschränkt werden).
Das ist ziemlich obskur (ich habe so etwas in den letzten 15 Jahren nur ein paar Mal benutzt). Ich gebe aber offen zu, dass ich oft Dinge iterativ und interaktiv erledigt habe, die wahrscheinlich effizienter hätten erledigt werden können, wenn ich mir die Zeit genommen hätte, die richtige Beschwörungsformel zu finden.
Eine weitere sehr nützliche vi ou ex Befehl ist :r
um den Inhalt einer anderen Datei einzulesen. So: :r foo
fügt den Inhalt der Datei mit dem Namen "foo" in die aktuelle Zeile ein.
Stärker ist die :r!
Befehl. Damit werden die Ergebnisse eines Befehls gelesen. Es ist dasselbe wie das Anhalten des vi Sitzung, das Ausführen eines Befehls, das Umleiten seiner Ausgabe in eine temporäre Datei, das Fortsetzen Ihrer vi Sitzung und das Einlesen des Inhalts aus der temporären Datei.
Noch leistungsstärker sind die !
(Peng) und :... !
( ex bang) Befehle. Diese führen ebenfalls externe Befehle aus und lesen die Ergebnisse in den aktuellen Text ein. Allerdings filtern sie auch eine Auswahl unseres Textes durch den Befehl! So können wir alle Zeilen in unserer Datei sortieren mit 1G!Gsort
( G
ist die vi "goto"-Befehl; er springt standardmäßig in die letzte Zeile der Datei, kann aber mit einer Zeilennummer versehen werden (z. B. 1, die erste Zeile). Dies ist gleichbedeutend mit dem Befehl ex Variante :1,$!sort
. Schriftsteller verwenden oft !
mit dem Unix fmt ou falten Hilfsprogramme für die Neuformatierung oder den "Zeilenumbruch" von Textabschnitten. Ein sehr gebräuchliches Makro ist {!}fmt
(Umformatierung des aktuellen Absatzes). Programmierer verwenden es manchmal, um ihren Code oder nur Teile davon durchlaufen zu lassen Einzug oder andere Code-Umformatierungswerkzeuge.
Die Verwendung des :r!
y !
Befehle bedeutet, dass jedes externe Dienstprogramm oder jeder Filter als eine Erweiterung unseres Editors behandelt werden kann. Ich habe sie gelegentlich mit Skripten verwendet, die Daten aus einer Datenbank abrufen, oder mit wget ou Luchs Befehle, die Daten von einer Website abrufen, oder ssh Befehle, die Daten von entfernten Systemen abrufen.
Eine weitere nützliche ex Befehl ist :so
(kurz für :source
). Damit wird der Inhalt einer Datei als eine Reihe von Befehlen gelesen. Wenn Sie vi führt es normalerweise implizit eine :source
auf ~/.exinitrc
Datei (und Vim tut dies normalerweise am ~/.vimrc
natürlich). Der Vorteil ist, dass Sie Ihr Editorprofil im Handumdrehen ändern können, indem Sie einfach einen neuen Satz von Makros, Abkürzungen und Editoreinstellungen einfügen. Wenn Sie raffiniert sind, können Sie dies sogar als Trick zum Speichern von Sequenzen von ex Bearbeitungsbefehle, die bei Bedarf auf Dateien angewendet werden können.
Ich habe zum Beispiel eine siebenzeilige Datei (36 Zeichen), die eine Datei durchläuft wc und fügt einen Kommentar im C-Stil am Anfang der Datei ein, der diese Wortzahldaten enthält. Ich kann dieses "Makro" auf eine Datei anwenden, indem ich einen Befehl wie: vim +'so mymacro.ex' ./mytarget
(Die +
Befehlszeilenoption zu vi y Vim wird normalerweise verwendet, um die Bearbeitungssitzung bei einer bestimmten Zeilennummer zu beginnen. Es ist jedoch eine wenig bekannte Tatsache, dass man die +
von jedem gültigen ex Befehl/Ausdruck, wie z.B. ein "source"-Befehl, wie ich es hier getan habe; für ein einfaches Beispiel habe ich Skripte, die aufrufen: vi +'/foo/d|wq!' ~/.ssh/known_hosts
um einen Eintrag aus meiner SSH-Datei "Bekannte Hosts" zu entfernen, während ich eine Reihe von Servern neu importiere).
Normalerweise ist es viel einfacher, solche "Makros" mit Perl oder AWK zu schreiben, sed (was in der Tat so ist wie grep ein Dienstprogramm nach dem Vorbild des ed Befehl).
Le site @
ist wahrscheinlich der obskurste Befehl vi Befehl. In den Kursen für fortgeschrittene Systemadministration, die ich seit fast einem Jahrzehnt gelegentlich gebe, habe ich nur sehr wenige Leute getroffen, die ihn jemals benutzt haben. @
führt den Inhalt eines Registers aus, als wäre es ein vi ou ex Befehl.
Beispiel: Ich verwende oft: :r!locate ...
um eine Datei auf meinem System zu finden und ihren Namen in mein Dokument einzulesen. Von dort aus lösche ich alle überflüssigen Treffer, so dass nur noch der vollständige Pfad zu der Datei übrig bleibt, an der ich interessiert bin. Anstatt mühsam Tab -durch jede Komponente des Pfades zu gehen (oder schlimmer noch, wenn ich auf einem Rechner festsitze, der keine Unterstützung für Tabulatorvervollständigung in seiner Kopie von vi ) Ich benutze einfach:
0i:r
(um die aktuelle Zeile in eine gültige :r Befehl),
"cdd
(um die Zeile im Register "c" zu löschen) und
@c
diesen Befehl ausführen.
Das sind nur 10 Tastenanschläge (und der Ausdruck "cdd
@c
ist für mich praktisch ein Fingermakro, so dass ich es fast so schnell tippen kann wie ein gewöhnliches Wort mit sechs Buchstaben).
Ein ernüchternder Gedanke
Ich habe nur an der Oberfläche gekratzt vi und nichts von dem, was ich hier beschrieben habe, ist auch nur ein Teil der "Verbesserungen", für die vim ist benannt! Alles, was ich hier beschrieben habe, sollte mit jeder alten Kopie von vi von vor 20 oder 30 Jahren.
Es gibt Menschen, die wesentlich mehr von den folgenden Substanzen verwendet haben vi als ich es jemals tun werde.