orm@doc-tcpip.org

Erstellt: Mai 2001 - Letzte Modifikation: März 2015

[ Main | Local ]


Eine kleine VI Reference


Der VI - eine Standortbestimmung

Ich bin vi-Fan, der vi ist der größte Editor aller Zeiten - mindestens. Ich finde auch nicht, daß er nicht intuitiv sei - völliger Blödsinn. Folgende Aussagen treffen sicher zu: Die Eintrittsschranke liegt sehr hoch, man kann nicht mal eben einen Text editieren. Dafür bietet der vi enormen Leistungsumfang, ist absolut portabel, überall vorhanden und gut zu konfigurieren. Und wer ihn nicht bedienen kann, wirds auch sonst zu nichts bringen.

Hier der Inhalt dieser Seite. Typische Probleme sind hier gesondert aufgeführt:
Wie mache ich was - allerlei Praktisches
Ansonsten die vi-Referenz:
Das absolute Minimum
Bewegen im Text
Einfügen und Löschen von Text
Suchen im Text
Editieren von Text
Editieren von Textteilen - Bereiche
Öffnen und Speichern von Files
Editieren vieler Files
Kopieren zwischen Files
Mehrere Fenster öffnen
Die Textpuffer
Die Textmarker
Das "mappen" von Tasten, Abkürzungen und das .exrc File
Das Erstellen von Macros

Das absolute Minimum

Die absoluten Minimal-Kenntnisse im Schnelldurchgang:
Ein File zum editieren öffnen bzw. neu anlegen:
vi filename
Dann mit den Pfeiltasten oder den Tasten j, k, h, l die Stelle suchen, wo man was editieren möchte. Danach kommt man mit der Taste i in den Modus zum editieren und kann schreiben.
Löschen geht mit ESC x (ein Buchstabe) oder mit ESC dd (eine Zeile). ESC D löscht den Rest einer Zeile.
Nach getaner Arbeit kommt man mit ESC : wq aus dem File raus - es wird dabei gesichert. Hat man was versaubeutelt, dann kann man mit ESC : q! das File ohne Sichern verlassen.

Viele Dinge lassen sich am Doppelpunkt für die aktuelle Session einstellen. Sollen solche Setzungen beim Starten da sein, so muss man sie ins rc File eintragen.

:set            - zeigt alle Werte, die sich vom Default unterscheiden
:set all        - zeigt alle Werte
:set foo?       - zeigt den Wert von foo
:set foo&       - auf den Default-Wert setzen
:setlocal foo   - nur für diese Session

:verbose set foo?   - wo wurde foo zuletzt gesetzt?

Automatisch Einrücken:
:set tabstop=4        - ein Tab wird 4 Stellen lang
:set expandtab        - es wird aber nicht das Tab Zeichen (<09>) benutzt
:set shiftwidth=4     - Einrücken ist 4 Stellen
:set autoindent       - Anschalten
:set smartindent      - Achtet auf den code
:set pastetoggle= - im .vimrc - beim pasten wird nicht eingerückt
:set paste            - wie oben im Editor
ctrl-t, ctrl-d        - rückt die aktuelle Zeile ein/aus

Syntax higligthing anschalten:
:syntax on/off

Bestimmte File Extensionen einem Syntax Typ zuordnen:
Lokal file anlegen: ~/.vim/filetype.vim
Mit dem Inhalt:

" SQL ist das Format unserer osp files
au BufNewFile,BufRead *.osp     setf sql

Und alle *.osp werden als SQL Code erkannt.

Globales File liegt hier: 
/usr/share/vim/vim74/

Suchen case insensitiv:
/blabl\c
oder 
:set ignorecase (set ic)
später
:set noic

Wenn man ignorecase per standard setzt, kann man umgekehrt den Case erzwingen mit \C.
Es gibt auch noch smartcase, da wird case insensitive gesucht, wenn
Gross und Klein gemischt im Key vorkommen.
[Seitenanfang]

Bewegen im Text

Wo bin ich im Moment? CTRL-G zeigt das aktuelle File, die aktuelle Zeile sowie die aktuelle Spalte. Und als Goodie noch den Ort in Prozent bezogen auf das ganze File sowie die Gesamtanzahl der Zeilen.


Alle Befehle können mit einem Zähler abgesetzt werden:
4b springt an den Anfang des 5. folgenden Wortes.

h Ein Zeichen nach Links
l Ein Zeichen nach Rechts
w Ein Wort nach Rechts
b Ein Wort nach Links

W springt an den Anfang des nächsten Wortes
B springt an den Anfang des Wortes
e springt an das Ende des Wortes
E springt an das Ende des nächsten Wortes

k Eine Zeile nach oben (geht auch -)
j Eine Zeile nach unten (geht auch +)

0 An den Zeilenanfang
$ An das Zeilenende - 5$ Ende Zeile 5 von aktueller Zeile
^,_ Zum ersten Wort ohne Leerzeichen davor (Beginn der Zeile/Spalte)
+,- Eine zeile vor bzw. zurück.

G an das Textende
1G an den Textanfang
[x]I springt in die x-te Spalte.

Auch hier kann man wieder mit Zählern arbeiten:
10G springt in die 10. Zeile des Textes.
10j springt 10 Zeilen vorraus.
10H springt 10 Zeilen unter den Seitenanfang.


CTRL B springt einen Bildschirminhalt zurück
CTRL F springt einen Bildschirminhalt voraus
CTRL D springt einen halben Bildschirminhalt zurück
CTRL U springt einen halben Bildschirminhalt voraus

Sehr praktisch ist auch folgendes Kommando:
z RETURN bringt die Zeile mit dem Cursor an den oberen Rand des Bildschirmes
z- bringt die Zeile mit dem Cursor an den unteren Rand des Bildschirmes
z. bringt die Zeile mit dem Cursor in die Mitte des Bildschirmes

[Seitenanfang]

Einfügen und Löschen von Text

i Einfügen vor Cursor
a Einfügen nach Cursor

I Einfügen am Zeilenstart
A Einfügen am Zeilenende

p Pasten in der nächsten Zeile
P Pasten am Cursor

r Ein Zeichen ersetzen
5rU Fünf Zeichen mit U ersetzen
R Überschreiben

cw Ein Wort ersetzen
C,c$ Ändern bis zum Ende der Zeile

dh Löschen von einem Zeichen zurück (links)
dl Löschen von einem Zeichen vorraus (rechts)

db Löschen von einem Wort zurück (links)
dw Löschen von einem Wort vorraus (rechts)

dB Löschen von einem "nonblanc" Wort zurück (links)
dW Löschen von einem "nonblanc" Wort vorraus (rechts)

d$ Löschen bis zum Zeilenende
d0,d^ Löschen bis zum Zeilenanfang

dL Löschen des Bildschirminhaltes
dG Löschen bis zum File-Ende
de Löschen bis zum Wort-Ende

Mit c statt d: dann kommt man direkt im den Edit Modus

Die meisten Kommandos haben noch eine andere Form:
x ist dl
X ist dh

D ist d$
dd ist 0d$

C ist c$
cc ist0c$

Jedes der genannten Kommandos kann man wiederholt ausführen, indem man die Punkt (.) Taste drückt. Außerdem kann man natürlich auch Bereiche im Text angeben:
ESC 10yy kopiert die aktuelle Zeile und 9 weitere in den Speicher
ESC 10dd löscht dieselben Zeilen nach dem Erstellen der Kopie

Es ist auch möglich, bis zu einem bestimmen String zu löschen:
d/string löscht bis string gefunden wird.

Oder eine bestimmt Anzahl von Zeilen löschen:
dZahlj löscht Zahl Zeilen nach unten (wegen des j)
d5G löscht 5 Zeilen nach unten, Start in der aktuellen Zeile (Cursor)
Setzt man diese Befehle ab, so wird vom Cursor bis zum ersten Buchstaben des Such-Strings gelöscht (das ist der vi-mode). Mit den folgenden Befehlen geht das auch alles, aber im ex-Mode - daher wird immer von Zeile zu Zeile gelöscht.

:1,/^[ ]*$/d löscht bis zur ersten leeren Zeile.

:1,/Seppel/d löscht alle Zeilen bis zur Zeile mit "Seppel".

:/Seppel/d löscht die nächste Zeile, in der "Seppel" vorkommt.
Das kann man "globalisieren":
:g/Seppel/d löscht alle Zeilen, in der "Seppel" vorkommt.

Die Logik kann man auch umdrehen:
:v/Seppel/d löscht alle Zeilen, in der "Seppel" nicht vorkommt.

:/Seppel/+2d löscht die zwei Zeilen, die auf die Zeile mit "Seppel" folgen.

:/Seppel/,/Kasperl/d löscht ab der Zeile mit "Seppel" bis zur Zeile mit "Kasperl".

:.,/Seppel/m456 löscht von hier (der Punkt) bis zur Zeile mit "Seppel" und fügt das Ganze nach Zeile 456 wieder ein.

:1,/^[ ]/d löscht bis zur ersten Zeile, die mit 4 Leerzeichen beginnt.

Wer aufgepasst hat, der hat jetzt verstanden, wie es geht: Man gibt immer einen Bereich an (Strings, Variablen oder Zahlen, auch gemischt, durch ein Komma getrennt) und eine Aktion (Löschen, Kopieren ...).

Hier eine kleine Liste der Regular Expressions, die der vi kennt.

 
. jedes Einzelzeichen (keine neue Zeile)
* jede Anzahl des vorstehenden Zeichen
^ folgendes Zeichen, wenn am Beginn einer Zeile
$ vorhergehendes Zeichen, wenn am Ende einer Zeile
[ ] Zeichenklasse: alles, was in den Klammern steht
[^] Zeichenklasse: alles, was nicht in den Klammern steht
\( \) String speichern für spätere Benutzung 
\< folgende Zeichen, wenn am Anfang eines Wortes
\> folgende Zeichen, wenn am Ende eines Wortes
\ Escape Zeichen, um die Sonderfunktion aufzuheben
\n n=Nummer, wiederholt vorherige Eingabe n-mal
& vorherige Suche wiederholen
~ vorherige Ersetzung wiederholen
\u Umwandlung in Großbuchstaben (ein Zeichen) 
\U Umwandlung in Großbuchstaben (mehrere Zeichen) 
\l Umwandlung in Kleinbuchstaben (ein Zeichen) 
\L Umwandlung in Kleinbuchstaben (mehrere Zeichen) 
\e Schaltet \u und \l aus.
\E Schaltet \U und \L aus.
Gross- und Kleinschreibung
~ am Cursor Case toggeln
3~ 3 Zeichen toggeln
g~iw im aktuellen Wort toggeln
g~~ / V~~ Zeile toggeln
g~3w drei Worte toggeln
g~$ bis Ende der Zeile toggeln
Das alles geht auch mit U und u statt ~ :
gUU / guu ==> Gross / Klein schreiben
Oder:
%s/.*/\L&/    (\U) ==> Gross / Klein schreiben
tr '[:upper:]''[:lower:]' 

[Seitenanfang]

Suchen im Text

fx nach rechts bis x gefunden ist
Fx nach links bis x gefunden ist

tx nach rechts bis x gefunden ist, Cursor auf die Stelle davor
Tx nach links bis x gefunden ist, Cursor auf die Stelle davor

/string Suche String nach unten
?string Suche String nach oben

n nächster Treffer in die eingestellte Richtung.
N nächster Treffer in die andere Richtung.

/^string\> findet die Zeile, die mit String beginnt.

/^string$ findet die Zeile, in der nur string steht.

/^$ findet leere Zeilen.
/^..*$ findet die Zeilen mit mindestens einem Zeichen.
/^.....$ findet die Zeilen mit genau fünf Zeichen.

/^\. findet die Zeilen, die mit einem Punkt beginnen.
/^[^\.] findet die Zeilen, die nicht mit einem Punkt beginnen.
/^\.[A-Z0-9] findet die Zeilen, die mit einem Punkt, gefolgt von Großbuchstabe oder Zahl beginnen.
/[Ss]tring findet String und string.

/[Ss][gG] findet Sg, sg, SG und sG.

/[A-Z][A-Z]* findet einen oder mehr Großbuchstaben.
/Str[aeiou]ng findet Strang, Streng etc..

/Str[^aeiou]ng findet alle Strings ohne Vokal.

/Str.ng findet alle Strings - für den Punkt kann jedes Zeichen stehen.

Hier gibt es auch wieder einen weiteren Modus mit den ex-Kommandos. Das Such-Kommando lautet hier g

[Seitenanfang]

Editieren von Text

Ich will einen Buchstabenlöschen und rechts neben dem Nächsten wieder einfügen:
xp tauscht zwei Buchstaben
Xp tauscht zwei Buchstaben, aber anders herum
Dabei kann ich mich mit h, l sowie j, k im Text bewegen. Ich kann auch Zeilen tauschen. Dabei kann ich mich auch im Text bewegen:
ddp Tauscht zwei Zeilen, die Gelöschte wird nach der Folgenden eingefügt.
ddkp Tauscht zwei Zeilen, die Gelöschte wird vor die darüberstehende Zeile kopiert. Mit mehr "k" springe ich mher Zeilen nach oben (mit "j" nach unten).

Vertauschen von Worten:

wort1:wort2
wort1:wort2 
Das erste mit dem zweiten Wort tauschen:
s/^\([^"]*\):\([^"]*\)/\2:\1/
wort2:wort1 
wort2:wort1 
Man kann dabei den ":" ersetzen, oder Sachen Einfügen im Ausdruck rechts:
s/^\([^"]*\):\([^"]*\)/Ich habe \2 mit \1 getauscht../
Ich habe wort2 mit wort1 getauscht..
Ich habe wort2 mit wort1 getauscht..
Dabei muss man beachten:

:s/^\([^ "]*\) \([^ "]*\)/\2:\1/ Der Blank ist hier ein Wort
:s/^\([^"]*\) \([^"]*\)/\2:\1/ Der Blank gehört hier zum Wort

Man kann alles mit einer Such-Option kombinieren:
:g/blabla/s/^\([^"]*\) \([^"]*\)/\2:\1/

Es werden nur Zeilen bearbeitet, in denen "blabla" vorkommt.

:g/^$/d Löscht alle Leerzeilen

:%s/\<./\u&/g
erster Buchstabe aller Wörter werden zu Großbuchstaben.

:%s/.*/\L&/ Das ganze File wird kleingeschrieben.

Mit dem Größer/Kleiner Symbol kann man Tabulatoren einfügen:
>>
fügt einen Tabulator ein,
<<
entfernt ihn wieder.
Mit einem Zähler bestimmt man die Anzahl der Zeilen, die betroffen sind.

Lange Wörter kann man abkürzen und die Kurzform speichern:
:ab dons Donaudampfschifffahrtskapitän

Tippt man jetzt dons, dann schreibt vi Donaudampfschifffahrtskapitän.

.
Groß- und Kleinschreibung läßt sich mit der Tilde schalten. Man kann angeben, wieviele Zeichen betroffen sein sollen:

10~ schaltet in die andere Schriftart für die folgenden 10 Zeichen.

Man kann ein File sortieren lassen. Das geht mit dem normalen sort-Befehl:
:%!sort sortiert das ganze File (geht auch Zeilenweise mit Zähler)

Manchmal hat man Files, die keine Zeilumbrüche mitbringen - der ganze Text steht in einer Zeile (Wenn DAUs Emails verschicken...). Dann kann man das fmt-Kommando nutzen (ist nicht immer installiert..).
Das geht so:
:1,$!fmt -sw66

In diesem Fall werden die im Text vorkommenden Zeilen an den Wortgrenzen umgebrochen, sodaß Zeilen mit maximal 66 Zeichen entstehen. Es werden keine Wörter getrennt, und die entstandenen Zeilen werden nicht aufgefüllt (das ist die -s Option). Es gibt noch ein paar Optionen mehr, siehe man-Page.
Man kann auch direkt :9!!fmt -sw66 tippen. Praktisch ist auch !}fmt, was einen Absatz formatiert.
.

Man kann Speicherinhalte als Befehle ausführen:
@b führt den Inhalt von Buffer b als Kommando aus

Ein Beispiel: Ich schreibe in eine Zeile ein großes G. Dann lösche ich das in den Buffer a (ESCAPE " a d RETURN). Jetzt kann ich dieses "Kommando" ausführen (ESCAPE @ a) und ich lande am Ende des Dokumentes.

Oft ist es nützlich, wenn man die Steuerzeichen (Neue Zeile, Tabulator..) des Textes sehen kann. Das kann man mit dem Befehl
:set list
erreichen. Das Zeilenende wird durch "$" angezeigt, Tabulatoren durch "^I".

[Seitenanfang]

Editieren von Textteilen - Bereiche

:% heißt, das Kommando soll für den ganzen Text gelten
:1,. heißt, das Kommando gilt von Zeile 1 bis zur aktuellen Zeile

:.,$ von der aktuellen Zeile bis zum Ende des Textes
:14,45 von der Zeile 14 bis zur Zeile 45
:14;45 von der Zeile 14 bis zur Zeile 45. Die aktuelle Zeile wird auf die Zeile 14 gesetzt

:.,+4 von der aktuellen Zeile 4 Zeilen weiter
:n von der aktuellen in Zeile n
:'a in die mit a markierte Zeile
:a+4,a-4 4 Zeilen vor und nach der mit a markierten Zeile




[Seitenanfang]

Öffnen und Speichern von Files

Das aktuell bearbeitet File kann man umbenennen:
:f Name benennt das File nach Name um. Das Original-File bleibt erhalten.

Will man einen Teil des aktuellen Files in ein anderes File speichern, so kann man folgendes tun:
:10,100w >> Name speichert die Zeilen 10 bis 100 in das File Name

Mit % kann man eine Kopie des aktuellen Standes eines Files machen:
:w %.kopie
(Also: mein_file wird als mein_file.kopie gespeichert..)

Es ist möglich, ein File an bestimmten Stellen zu öffnen:

Ein File an einer bestimmten Linie öffnen:

vi +n filename öffnet das File filename auf der Linie n.

Oder es wird nach einem bestimmten String gesucht:

vi +/string filename öffnet das File filename an der Linie, in der der String string steht.

.
Hat man ein File dadurch zerschoßen, das man den vi gekillt hat (Maschinencrash z.B.) dann kann man das letzte File meist aus dem temporären File wieder herstellen.
Dazu gibt es den Schalter -r. Man ruft den vi also so auf:
vi -r der vi zeigt jetzt alle temporären Files an.
vi -r filename nimmt als Input das letzte temporäre File, das zum File "filename" gehört. Das kann man dann prüfen und neu abspeichern.

Oft hat man ein Problem mit großen Files. Es kommt beim Öffnen eine Meldung, das der Speicherplatz nicht ausreicht.
Der VI legt beim Öffnen das File als Kopie in den Speicher, und arbeitet auf dieser Kopie. Erst beim Schließen wird das File wieder Syncronisiert. Ist im entsprechenden Verzeichnis nicht genug Platz, so kommt es zu dieser Meldung. Mit
: set dir sieht man das aktuelle Verzeichnis, in das der VI das temporäre File legt. Mit
: set dir=/neues/verzeichnis kann man ein anderes Verzeichnis setzen. Das kann man im File exrc festlegen oder beim Aufruf per
vi -c "set dir=/neues/verzeichnis"

[Seitenanfang]


Editieren vieler Files

Man kann beliebig viele Files im Zugriff haben. Das geht einfach mit dem Aufruf vi xx vvv yyy oder sogar mit vi * wenn man weiß, was man tut.

Folgende Befehle sind in diesem Fall wichtig:
:n springt in das nächste File, warnt wenn das aktuelle nicht gesichert wurde.
CTRL g zeigt den Namen des Files, das momentan in Arbeit ist.
:f dasselbe, zusätzlich kann man bei Angabe eines Namens das File umbenennen.
:args zeigt die Files, die editiert werden - das aktuelle File ist hervorgehoben.


Man kann aus einem File noch ein anderes editieren:
Man sichert mit :w und kann mit :e xxxx das andere File öffnen.

Mit den Zeichen # und % springt man zwischen den Files. % ist das aktuelle File, # das alternative (e# ist immer "das andere File").

Mit % kann man zb. eine Kopie des aktuellen Standes eines Files machen:
:w %.kopie
(Also: mein_file wird als mein_file.kopie gespeichert..)

[Seitenanfang]


Kopieren zwischen Files

Das macht man einfach mit Hilfe der "named buffers". Diese werden beim Wechsel von einem File ins andere (egal ob man das File neu öffnet oder schon beim Aufruf des vi angegeben hat - es muß nur dieselbe vi-Session sein) nicht gelöscht.
Man schneidet was aus, legt es in den Named Buffer und öffnet ein anderes File. Hier ein kleines Beispiel:

"a8yy legt die folgenden 8 Zeilen in den Buffer a. ("A8yy würde die folgenden 8 Zeilen an den Buffer a anhängen - der Buffer wird geleert, wenn man ihn wieder als a anspricht)
Im neuen File legt man die 8 Zeilen wieder hin:
"ap

[Seitenanfang]

Wie mache ich was - allerlei Praktisches

Ich möchte...
... Teile eines Files in ein anderes kopieren!
... verschiedene Textstücke in einen Speicher kopieren!
... bis zu einem bestimmten Wort löschen!
... für die folgenden 32 Zeilen einen Tabulator einfügen!
... alle Tabulatoren, End of Line etc. sehen!
... etwas, was ich vor 5 Minuten gelöscht habe wiederholen!
... nach einem unfreiwilligen Ausstieg mein modifiziertes File wiederhaben!
... den VI nur für HTML-Text (oder sonst was) nutzen!
... zwei Files zugleich editieren!
... 100 gleiche Zeilen schreiben, in denen sich nur 1 Wort ändert!
... alle leeren Zeilen löschen!
... etwas nehmen und es bei Zeile xx wieder einfügen!
... ein File an einer bestimmten Stelle öffnen!
... lange Linien in einem File auf 80 Zeichen umbrechen!
... eine lange Namensliste sortieren!
... ein riesiges File öffnen!

[Seitenanfang]

Mehrere Fenster im vi

Das ist ein Feature was meiner Erfahrung nach sehr stark von der Implementation des vi abhängt - es kann also sein, das einige oder alle der folgenden Kommandos nicht funktionieren. Dann hat man halt Pech gehabt.

Man kann einmal den vi mit dem Schalter -o aufrufen. So öffnet vi -o file1 file2 file3 jedes File in einem eigenen Fenster. Der Bildschirm wird dabei horizontal geteilt, mit vi -O wird der Bildschirm vertikal geteilt. Mit vi -o N kann man N Fenster öffnen.

In einige vi's geht es mit CTRL W S. Sollte dann der Bildschirm eingefroren sein, dann kommt man mit CTRL Q wieder ans Arbeiten.

Zum Schluß gibt es noch das split-Kommando: mit :N split (wobei N die Höhe des Fensters angibt) kann man das aktuelle Fenster in zwei teilen. Vertikal geht das auch: :N vsplit. Will man während man ein File bearbeitet, ein anderes öffnen, dann braucht man die Kommandos new und vnew: :N new file1. Es geht auch im Read-only Modus: sview. Um die offenen Fenster zu wechseln, schließen oder auszublenden dienen die Befehle quit, close, hide und only.

Man wechselt zwischen den Fenstern mit CTRL-W w. Mit h, j, k, l wechselt man in die umliegenden Fenster. Mit t und b kann man sich nach oben oder nach unten im aktuellen Fenster bewegen.

Die gleichen Kommandos in Grossbuchstaben ermöglichen es, Fenster zu verschieben.

Mehrere Fenster kann man mit Kommandos parallel bedienen, mit all. So schliesst :qall alle Fenster, :wall schreibt alle Fenster etc.

[Seitenanfang]

Die Textpuffer

Es gibt im vi genau 36 Textpuffer, die der User nutzen kann. Man unterscheidet zwischen statischen Puffern, von denen 26 möglich sind, und dynamischen Puffern, von denen es 10 gibt. Die Puffer des vi haben eine spezielle Eigenschaft: man kann einen Befehl ausschreiben, ihn in einen Puffer kopieren, und dann den Puffer mit dem Klammeraffen ("@") aufrufen - der Befehl wird ausgeführt. Das ist eigentlich nicht von praktischen Nutzen, jedoch gut zu wissen.

Statische Puffer

Diese Puffer werden mit den Buchstaben des Alphabeths benannt und ändern sich nur, wenn der User sie explizit anspricht. Es macht einen Unterschied, ob man den Puffer mit großen oder kleinen Buchstaben benennt: benutzt man Großbuchstaben, so wird der Text an den Inhalt des Puffers angefügt. Mit Kleinbuchstaben wird der Puffer neu überschrieben.

Dynamische Puffer

In diese Puffer schreibt der vi gelöschte Zeilen oder Zeichen. Die Puffer werden mit den Zahlen 1 - 9 benannt. Löscht man etwas, so wird das in den ersten Puffer (der Puffer "0") gelegt. Bei weiterem Löschen wandert der Inhalt in der Hierarchie der Puffer weiter hoch. Wirklich gelöscht ist es erst, wenn der Puffer 9 überschrieben wird.
Je nachdem, wie viel man löscht, kann man die Information solange wieder aus dem Puffer holen, bis sie im hypothetischen Puffer 10 angekommen ist... (das gilt nur für ganze Zeilen).

Laden und Leeren der Puffer

Das Laden geschieht mit den Anführungsstrichen ("). Ein Ladekommando setzt sich immer zusammen aus dem Namen des Puffers und einem Bewegungskommando (delete, yank). Hier eine Reihe Beispiele:
"a5yy kopiert die fünf folgenden Zeilen in den Puffer a.
"A3yy hängt an den Puffer a weitere 3 Zeilen an.
"fy'd kopiert von Cursor bis zur Textmarke d alles in den Puffer f.
Mit so einem Befehl kopiert man immer bis zur Textmarke, die Marke selbst also nicht mehr.

Möchte man die nummerierten Buffer durchsuchen, so geht man folgenderart vor:
Zuerst ruft man den Buffer 1 auf
"1p
Die entsprechende Zeile wird eingefügt. War es das nicht, so entfernt man die Zeile mit
u und wieder holt mit dem ..
Das wird wiederholt, bis die Buffer alle geprüft sind - dann ist der String verloren...
Einzelne Buchstaben oder Wörter werden erst garnicht in die nummerierten Buffer gelegt.

Zum Einfügen werden auch die Anführungsstriche (") benutzt. Im Kommando wird jetzt statt des Bewegungskommandos das Pastekommando (p oder P) gegeben. Das kleine p fügt den Pufferinhalt nach dem Cursor ein, das große P fügt vor dem Cursor ein.

[Seitenanfang]

Die Textmarker

Der vi verfügt über 26 Textmarker, die durch die Buchstaben des Alphabets benannt werden. Ein Marker wird mit dem Befehl "m" und der Angabe des Namens gesetzt. Der gewählte Punkt ist dann die Referenz für Bewegungen, Löschen, Kopieren etc.
Beispiele:
ma setzt den Marker a.
Auf diesen kann man sich jetzt bei der Bewegung beziehen:
`a (Akzent) springt genau auf die Marke,
'a (Hochkomma) an den Anfang der Zeile der Marke.

Damit kann man ganze Textblöcke löschen oder Verschieben, z.B. zu Beginn des Bereiches mit mq einen Marker setzen, an das Ende des Bereiches laufen und den Textblock ausschneiden oder kopieren: y'q bzw. d'q. Das ist dann im Puffer, und man kann es an beliebiger Stelle wieder Einfügen.

[Seitenanfang]

Abkürzungen

Abkürzungen sind sehr einfach und praktisch. Ich will z.B. nicht immer "Dynamic Host Configuration Protocol" ausschreiben. Also setze ich folgenden Befehl ab:

:abbr dhcp Dynamic Host Configuration Protocol

Wenn ich jetzt "dhcp" (mit Leerzeichen davor und dahinter) tippe, dann expandiert der vi das sofort zum langen Wort. Möchte ich jetzt einmal doch nur die 4 Buchstaben "dhcp" schreiben, dann kann ich entweder "dhcp^V" tippen (also d,h,c,p,CTRL-V, Leertaste) oder ich kann mit dem Kommando "unabbr" die Abkürzung zurücksetzen.
Es ist wichtig, sich zu merken, daß bei Abkürzungen der vi auf das Zeichen nach der eingebenen Sequenz wartet.

Mappen von Tasten

Hierbei wird die definierte Sequenz sofort expandiert, und man kann auch komplizierte Macros auf eine Tastenkombination binden. Dazu dient das Kommando "map". Es gibt zwei Möglichkeiten, die verschiedene Modi des vi benutzten.
map funktioniert mit Kommandosequenzen, die im Kommando Mode (also nach einem ESCAPE) eingegeben werden, während map! auf im Textmodus getippte Sequenzen reagiert.

map! - Text Mode

Die Eingabe des folgenden Befehls bringt den vi dazu, die Folge "dhcp" nicht mehr auf den Bildschirm zu bringen, sondern direkt zu ersetzen:

:map! dhcp Dynamic Host Configuration Protocol

Der "map!"-Befehl kann wie gehabt mit "unmap!" wieder aufgehoben werden und mit CTRL-V temporär umgangen werden. Man kann alle aktuellen Mappings durch eingeben von "map!" am Doppelpunkt sehen.

map - Kommando Mode

Wie im vorigen Abschnitt, nur das die definierte Sequenz im Kommando-Mode, also nach einem ESCAPE, benutzt werden muß. Der "map"-Befehl kann wie gehabt mit "unmap" wieder aufgehoben werden und mit CTRL-V temporär umgangen werden. Man kann alle aktuellen Mappings durch eingeben von "map" am Doppelpunkt sehen.

Das .exrc-File

Abkürzungen und Mappings kann man dem VI beim starten mitgeben. Es ist auch möglich, eine ganze Reihe anderer Steuerbefehle mitzugeben - und man kann pro Unterverzeichnis ein spezielles .exrc pflegen (z.B. für HTML und LaTex). So kann man verschiedene, spezialisierte VI-Instanzen laufen lassen. Über die Umgebungsvariable EXINIT kann bestimmt werden, wie der VI starten soll. Es ist auch jederzeit möglich, ein vorhandenes .exrc einzulesen:
:so .xxxx

Hier ein Beispiel .exrc:

" Ein Kommentar
set noautoindent
set showmode
set tabstop=8
...
ab c    < CENTER>
ab _c   < /CENTER>
ab hf   < A HREF="
ab _h   < /A>
...
" Ein Macro:
" CTRL X Nummer: H1 bis H2 (1-2)
map  ^X1 I< H1>^A< /H1> ^[D^[o
map  ^X2 I< H2>^A< /H2> ^[D^[o
...
Die Syntax ist eigentlich selbsterklärend, und zu den Macros kommen wir jetzt.

[Seitenanfang]

Macros

Das schreiben von Macros ist eigentlich sehr einfach, da es sich um Abfolgen von vi-Befehlen handelt, die man normalerweise auch so Absetzen kann. Aufgrund der Struktur der Buffer ist es innerhalb eines Macros zusätzlich möglich, Dinge zeitlich zu versetzen, also eine Eingabe zu machen, die erst nach der Eingabe an die richtige Stelle kopiert wird.

Die große Gefahr sind recursive macros, also Macros, die sich selbst während ihrer Ausführung erneut aufrufen. Ein Beispiel wäre folgendes Mapping: map! dhcp Das dhcp klasse sein. Hier ruft das Macro sich selbst auf und es kommt zur Katatrophe. Daher ist man gut beraten, wenn man sich seine Macros vorher gut anschaut und gründlich testet, bevor man sie eingibt oder im .exrc verewigt.

Hier einige nützliche Beispiele - der Fantasie sind keine Grenzen gesetzt. In den Macros müssen eine Reihe Steuersequenzen eingesetzt werden. Diese werden mit der CTRL-Taste (STRG-Taste) erzeugt. So ist ^X die Kombination CTRL-X etc. Ein spezieller Fall ist die Escape-Sequenz ^[, die man mit der Kombination CTRL-V und dann ESCAPE-Taste erhält. Da es Stuerzeichen sind, ist es nicht möglich, eine solche Zeile z.B. mit der Maus zu kopieren (greppen), da die Steuerzeichen verloren gehen.

map ^X1 I< H1>^A< /H1> ^[D^[o
Hier ist definiert, das die Tastenkombination CTRL-X auf einer gerade geschriebenen Zeile folgende Aktionen auslöst: Es wird am Anfang der Zeile die Header-1 Anweisung eingefügt, am Ende ausgeführt, bis zum Zeilenende gelöscht und eine neue Zeile zur Eingabe geöffnet.
map ^X^L o< /A>^[kO">^[I< A HREF="http://
Die Kombination CTRL-x + w führt dazu, das der unter dem Cursor liegende Text in eine HREF... Anweisung eingeführt wird. Der Cursor springt dann noch zur richtigen Stelle zur Eingabe des Links (URL).
map ^X^W a< /A>^[bbbi< A HREF="http://#">^[F#
Dasselbe für ein Wort (statt der ganzen Zeile).

Man kann Macros verketten - dazu dient der "=" Befehl. Damit ist es möglich, einige ärgerliche Begrenzungen bezüglich der Länge eines Macros zu überwinden.

[Seitenanfang]

Einfaches umbennen vieler Files

Der vi ist auch sehr praktisch beim Bearbeiten großer Mengen an Files, z.B. wenn man 1000 Files "name.txt" nach " name.html" umbenennen möchte:

Man öffnet den vi und geht in den Colon Mode:


:r !ls *.txt            # xyz.txt
:%s/.*/mv & &/          # mv xyz.txt xyz.txt
:%s/txt$/html/          # mv xyz.txt xyz.html
:w !sh
:q!

In der ersten Anweisung liest der vi ein Listing des Inhalts des Direktories ein. Das kann man natürlich auch noch editieren. Die zweite Anweisung sagt dem vi, den ganzen Ausdruck (.*) durch "mv & &" zu ersetzen. Der Ampersand steht dabei für den Ausdruck, der mit ".*" in den Buffer geschrieben wurde. Jetzt wird "txt" durch "html" ersetzt, und zwar nur, wenn es am Ende der Zeile steht, daher das "$". Man kann nun die Sache nochmal checken. Mit der Write-Anweisung schreibt man das Ergebnis nicht in ein File, sondern auf eine Shell, die jede Zeile als Kommando interpretiert und ausführt.

Das sieht im Beispiel so aus:
Im VI, nach einlesen mit ":r !ls *":

plautze1.jpg
plautze2.jpg
plautze3.jpg
plautze4.jpg
plautze5.jpg
Hier der Befehl, der folgende Zeile erzeugt:
Das ist das File plautze*.jpg ...
:.,5s/.*/Das ist das File & .../

Jetzt hat man oft das Problem, daß man am Filenamen etwas ändern möchte, was nicht am Ende steht. Zb. sollen alle Files sapPEUvg3.out nach sapGAGvg3.out umbenannt werden. Man erzeugt also wie oben folgende vi-Datei:

mv sapPEUvg0.out sapPEUvg0.out
mv sapPEUvg1.out sapPEUvg1.out
mv sapPEUvg2.out sapPEUvg2.out
mv sapPEUvg3.out sapPEUvg3.out
Jetzt muß man das zweite PEU jeder Zeile in GAG umschreiben; das macht einen Trick nötig, da vi die Zeilen von links nach rechts durchgeht. Daher kann man entweder jeweils die erste Instanz ändern, oder alle. Man ändert also alle PEU in einer Zeile in GAG, und ändert dann das erste GAG in PEU zurück:
:%s/PEU/GAG/g  ==> alle Namen haben jetzt das GAG.
:%s/GAG/PEU/   ==> nur das jeweils erste GAG auf der Zeile wird zum PEU.
Man kann auch richtig professionel vorgehen und zuerst das erste PEU in GAG umbenennen und dann die Worte tauschen:
g/GAG/s/^\([^ ]*\) \([^ ]*\) \([^ ]*\)/\1 \3 \2/
Das vertauscht auf jeder Zeile, die "GAG" enthält, das zweite mit dem dritten Wort; man erhält das gewünschte File und kann die Files umbennen.

Wenn man weiss, was man tut, dann kann man sich den Umweg über den vi sparen:

ls -d *.xxx | sed "s/.*\)\.xxx$/mv '&# '\1.old'/" | sh

Macht aus File bla.xxx das File bla.old.

ls -d | sed "s/[A-Z,a-z,0-9,.,_,-]*/mv '&' '&.html'/" | sh
[Seitenanfang]


[ Main | Local ]

[ Allgemein | UNIX | AIX | TCP-IP | TCP | ROUTING | DNS | NTP | NFS | FreeBSD | Linux | RPi | SMTP | Tracing | GPS | LW ]

Copyright 2001-2021 by Orm Hager - Es gilt die GPL
Feedback bitte an: Orm Hager (orm@doc-tcpip.org )