Gli utilizzatori di Linux più incalliti lo conoscono bene, perché con questo editor di testo si fanno molteplici operazioni, ma è complicato tanto quanto potente.
Vi è un editor modale, questo significa che quando si è in modo “comandi” i tasti eseguono operazioni sul buffer e quindi salvataggi, aperture e tante altre cose, mentre quando è in modalità “inserimento” consente di inserire e modificare il testo.
Quando il programma viene avviato è in modalità comandi, ci sono molti comandi per entrare in modalità inserimento, tra questi “i” è il più elementare, per ritornare in modalità comandi basta fare Esc. In modalità inserimento premere “x” per cancellare il carattere sul cursore e spostare il resto della riga a sinistra, “dd” per cancellare l’intera riga sul cursore.
Per sostituire un carattere non è necessario cancellare il carattere e riscriverlo, ma posizionarsi con il cursore sul carattere da modificare e poi premere “r” ed inserire il nuovo carattere.
Per uscire da vi salvando le modifiche nel file basta entrare in modo comandi e premere “ZZ“. Se in modalità comandi inseriamo i due punti ( : ) è possibile dare altri comandi come w ( write ), q ( quit ) ed il punto esclamativo per uscire senza salvare il buffer anche se è stato modificato.
Lo screen editor "vi" viene lanciato con il seguente comando:
vi [-r] [+comando] [file1 [file2 ... filen]]
dove:
-r opzione da utilizzare dopo un crash del sistema
(per recuperare le modifiche non memorizzate
relative al file);
+comando apre la sessione dell'editor eseguendo il "comando"
(sono significativi solamente i comandi di editor di
linea).
Nel caso in cui si specifichino più nomi di file da editare, 'vi'
entra in editing sul primo file indicato, e su richiesta (comando
':n') passerà in ordine ai successivi.
Questo editor visualizza una schermata di file alla volta,
permettendo di indirizzare il cursore con appositi comandi al
punto (carattere, parola, frase, paragrafo, riga, ...) dove si
vuole inserire o aggiornare il testo.
Per un corretto funzionamento è indispensabile conoscere l'esatto
tipo del terminale su cui si sta lavorando. Verrà quindi settata
la variabile TERM con la sintassi propria del sistema su cui si
lavora; per default, la sintassi standard è:
TERM=type ; export TERM
dove "type" corrisponde ad un nome di terminale (con tutte le
funzionalità ad esso legate) descritto nella libreria "terminfo".
In fase di entrata in "vi", compariranno sullo schermo le prime 24
righe del file richiamato (con "~" come primo carattere sulle righe
vuote), e ci si troverà in COMMAND MODE.
Quest'ultimo è uno dei tre possibili stati dell'editor "vi".
COMMAND MODE Il cursore è posizionato sul testo, la tastiera
è utilizzabile solo per richiedere l'esecuzione
di comandi, e non per introdurre testo.
I caratteri digitati non vengono visualizzati.
INPUT MODE Tutti i caratteri digitati vengono visualizzati
ed inseriti nel testo. Si passa in input mode ad
ogni richiesta di inserimento di testo.
DIRECTIVE MODE Ci si trova (tramite ":") posizionati con il
cursore nella linea direttive (l'ultima linea del
video) e si possono richiedere a "vi" tutti i
comandi per il controllo del file.
I passaggi di stato avvengono con i seguenti caratteri:
DIRECTIVE MODE -----> COMMAND MODE <RET>
COMMAND MODE -----> INPUT MODE oORia
INPUT MODE -----> COMMAND MODE <ESC>
COMMAND MODE -----> DIRECTIVE MODE :/?
All'interno del "vi" si è in grado di lanciare comandi appartenenti
alla shell da cui è stato richiamato il "vi" stesso, tramite
l'apposito escape alla shell (questo comando verrà trattato meglio
più avanti):
:!comando
Per quanto riguarda le cancellazioni, 'vi' ha un singolo buffer
senza nome, nel quale viene salvata l'ultima porzione di testo
cancellata, nove buffer numerati (1 2 ... 9) ed un insieme di
buffer individuati dalle lettere dell'alfabeto (a b ... z) a
disposizione dell'utente. I buffer, in caso di editing di più
file in successione, non vengono cancellati nel passare da un file
all'altro, permettendo così spostamenti di parte di testo tra
file diversi. Naturalmente possono anche essere utilizzati per
cancellazioni e ripristini o per spostamenti di parti di testo
all'interno di uno stesso file.
È importante ricordare che per 'vi':
- una parola è una qualsiasi sequenza di caratteri chiusa da uno spazio;
- una frase di testo è una qualsiasi sequenza di caratteri chiusa da '.', '!' oppure '?' seguiti da newline o da due spazi;
- un paragrafo è invece delimitato da una linea vuota.
COMANDI OPERATIVI
Tutti i comandi di spostamento si richiedono da COMMAND MODE.
SPOSTAMENTI DI BASEh 1 spazio a sinistra (come backspace) l 1 spazio a destra (come space) k 1 linea sopra (stessa colonna) j 1 linea sotto (stessa colonna) (in sostituzione di questi quattro caratteri, si possono anche utilizzare le frecce per spostarsi nelle diverse direzioni) G posizionamento sull'ultima linea del testo #G
OPERAZIONI SUL VIDEO^G mostra lo stato del file corrente (informazioni varie) := mostra il numero di linee del file :.= mostra il numero della linea corrente ^L refresh del video ^D si posiziona mezza pagina avanti (in INSERT MODE shifta indietro di un TAB) ^U si posiziona mezza pagina indietro ^F si posiziona sulla pagina successiva ^B
{ sposta il cursore all'inizio del paragrafo$ si posiziona alla fine della linea ^
ESC ESCAPE: fa uscire dall'INPUT MODE, per terminareZZ aggiorna sempre il file ed esce (da COMMAND MODE) :[#,#]w[!] [filename] WRITE: scrive senza uscire (nel file "filename", se viene specificato, altrimenti nel file corrente); vengono utilizzati "#,#" per specificare gli indirizzi 'from' e 'to' (da/a), e "!" (bang) per forzare la scrittura (cioè per riscrivere) Esempi: :1,5 w abcd scrive le linee da 1 a 5 nel file abcd :/from/,/to/ w efg scrive da 'from' a 'to' nel file efg :/from/,+5 w hij scrive da 'from' a 5 linee dopo nel file hij :x WRITE and QUIT: aggiorna, se necessario, ed esce :wq WRITE and QUIT: aggiorna ed esce :w !UNIX-CMD WRITE: scrive l'output e lo passa attraverso una pipe ad un comando UNIX Esempio: :1,10 w !lpr manda le prime 10 linee alla stampante :q[!] QUIT: esce senza salvare le modifiche (! 'bang' forza l'uscita)
UNDOu UNDO: annulla l'ultima modifica U UNDO: annulla tutte le modifiche fatte alla linea corrente fino a quando il cursore non è stato spostato dalla linea "[1-9]PASTE utilizza un comando PASTE per incollare uno dei buffer numerati; i buffer numerati immagazzinano le ultime 9 cancellazioni effettuate, con il metodo "first in last out". Solitamente si utilizzano per riportare sul file porzioni testo precedentemente cancellate Esempi: "1P "2p
CUT
YANKy<movesrch> esegue uno YANK fino a dove specificato da "move" o "search" Esempi: yw yank di una parola yfg yank fino a quando trova 'g' y#move esegue uno YANK fino a dove specificato da "#move" Esempio: y3j esegue lo yank di 3 linee verso il basso oltre alla linea corrente di partenza y/pattern/ esegue uno YANK fino a trovare 'pattern' (in avanti) y?pattern? esegue uno YANK fino a trovare 'pattern' (in dietro) y'<chr> esegue uno YANK fino al mark 'chr' (vedere la miscellanea per imparare come creare dei mark) Y, yy esegue uno YANK di una linea (quella corrente) #Y, #yy esegue uno YANK di "#" linee sottostanti "[char]YANK copia lo YANK in 'char'
PASTEP PASTE: incolla il contenuto del buffer prima del
f char FIND: cerca la successiva occorrenza di 'char'
COMANDI PER IL CONTROLLO DEI FILE
Si tratta di un approfondimento dei comandi dati da DIRECTIVE MODE
(":").
Nota: se in fondo al video compare un prompt ":" e non si riesce a
lavorare con vi, può significare che si è entrati
nell'editor di linea "ed". Digitare 'vi' al prompt per
rientrare in editor "vi" (è possibile invece confermare
l'entrata in "ed" digitando ^$).
:#,#<command>[!][filenm] formato generale; gli '#'
rappresentano comandi di movimento,
oppure numeri di linea per
indicare le posizioni da/a.
Uno dei '#' può essere:
+# #sotto -# #sopra
. linea corrente $ ultima linea
:s/<search>/<replace>/[#gc] SUBSTITUTE: sostituisce <search>
con <replace> una volta in una
linea, se è specificato 'g'
allora sostituisce tutto
all'interno della linea.
'c' serve per la conferma, '#'
serve per sostituire in "#" linee.
Vedere <SEARCH> e <REPLACE> per
maggiori informazioni su
questi comandi
<SEARCH> <SEARCH> può avere sub-espressioni,
\(exp1\)[junk]\(exp2\) definite con una coppia di "\(" e
"\(" (fino a 9 espressioni)
<REPLACE> <REPLACE> può avere descrittori
\# junk \# \# junk delle espressioni, definite da un
"\#", dove '#' è un numero 1 - 9
Esempio:
s/\(.*\)=\(.*\)/\2 = \1/
scambia LHS con RHS di un
segno 'uguale a'
in una linea con il formato:
[something] = [something]
:#1,#2g/<search>/<ex command> questo comando cercherà ogni
occorrenza di <search> compresa
tra le linee #1 e #2 ed eseguirà
il comando <ex command>.
L' "ex command":
s//<replace>/[gc]
cercherà <search> (// significa
l'ultima ricerca) e lo sostituirà con
<replace>.
Utilizzare altri comandi come
elencato sotto, quali "p" o "d".
#1,#2 c <text><.> CHANGE: cambia le linee da #1 a #2
con <text>; per uscire da questa
modalità, digitare un '.' (period)
da solo all'inizio di una linea.
:#1,#2 co #3 COPY: copia linee nello stesso
modo descritto sopra
:#1,#2 t #3 comando corrispondente a 'co'
:#1,#2 d DELETE: cancella le linee da
#1 a #2
Esempio:
:'a,'bd
cancella le linee dal mark
'a' fino a 'b'
:#1,#2 y "<alpha> esegue lo YANK di linee nel buffer
con nome <alpha>; se viene utilizzato
l'alfabeto maiuscolo, allora yank
aggiungerà al buffer
:e[!] [filename] esegue l'EDIT del file corrente("!"
indica una forzatura, per editare
'filename' se viene specificato);
nel caso in cui non sia presente la
forzatura, se si vuole editare un
nuovo file e quello corrente non è
stato salvato, viene rilasciato un
avvertimento ed il nuovo edit non
viene eseguito (sarà quindi
necessario salvare, oppure editare
con la forzatura; in quest'ultimo
caso vengono persi i cambiamenti
fatti nel file corrente)
:e# esegue l'EDIT alternativamente di
due file (è necessario editare un
altro file, e poi usare l'"e#" per
editare nuovamente il primo file)
:e # esegue l'EDIT del file alternato e
riprende all'ultima posizione del
cursore
:#1,#2 m #3 MOVE: sposta le linee tra #1 e #2
e le posiziona a #3
Esempi:
:10,15m25 sposta 5 linee
(comprese tra
la 10 e la 15)
alla linea 25
:1,.m $ sposta alla fine
del file le
linee comprese tra
la linea 1
e quella corrente
:#1,#2 p PRINT: stampa le linee indicate
(senza fare alcun cambiamento al
file)
:#1r[!] [filename] READ: legge il file corrente
(applicando le opzioni sopra
descritte); se sono specificati
il "filename" e "#1", allora
inserisce il file alla posizione
"#1" (l'inizio del file è la
linea 0, e la fine è $)
Esempio:
:r pippo
carica il file 'pippo' nella
posizione in cui si trova
attualmente il cursore
:r !UNIX-CMD READ: legge l'output del comando
UNIX 'UNIX-CMD' come input al file,
caricandolo nel buffer
:n[filenames][!] NEXT: edita il file successivo
nella lista degli argomenti; se
viene messa la forzatura '!',
non aggiorna il file corrente.
Nel caso in cui sia stato
specificato un elenco di file da
editare, vi edita i file uno alla
volta
Esempio:
:n a.c b.c c.c d.c
edita 4 file, cominciando
con a.c
e successivamente:
:n e.c f.c
aggiunge i file e.c ed f.c
alla lista, andando in
editing di e.c
Nota: con vi è possibile editare
molteplici file già con il
comando di lancio dell'editor
Esempio:
vi *.c
:args mostra i file che 'vi' stà
attualmente editando; dopo il
comando ":n" sopra riportato
nell'esempio, digitando ":args"
comparirà
[a.c] b.c c.c d.c
dove le parentesi [] includono il
file corrente
:rew [!] REWIND: ricomincia ad editare i
file a partire dal primo file
della lista; vedere il comando ":n"
:st[op] STOP: blocca il 'vi' ed esce alla
shell; per rientrare in 'vi',
digitare "fg" al prompt di UNIX
:sh lancia una shell (solitamente una
bourne shell); si ritorna
nell'editor con ^d
:!<command> esegue un comando UNIX, indicato
con 'command', all'esterno del 'vi'
Esempio:
:1,10 w !lpr
invia le prime 10 linee alla
stampante senza che sia
necessario creare un altro
file (cioè utilizza il file
senza causarne variazioni)
:!! ripete l'ultimo comando
':!<command>'
#!!<command> esegue il comando shell indicato
con 'command' e sostituisce il
numero di linee specificato
con '#' con l'output del comando;
se non viene specificato '#', il
default e' 1. Se il comando UNIX
si aspetta uno standard input,
allora le linee specificate
verranno usate come input
Esempio:
10!!sort
sorta le 10 linee successive
!$lt;lines><command> funziona come il precedente
comando '#!!<command>', tranne che
per il fatto che 'lines' è un
indirizzo di linea, o delimitatore,
necessario per poter eseguire
il comando.
Esempio:
!Gsort
sorta le rimanenti linee
del file
Il testo compreso tra la posizione
corrente del cursore ed il
delimitatore 'lines' è dato
in input a 'command' (ad esempio,
sort) e viene poi sostituito con
l'output del processo 'command'
lanciato. Delimitatori validi
possono essere, ad esempio, ')'
o '}' per dare in input a
'command' una frase o un
paragrafo.
Si noti che solo quando viene
digitato il delimitatore (che
può essere anche un
secondo punto esclamativo)
il cursore si posiziona sulla
linea delle direttive,
visualizzando '!'
& esegue solamente l'ultima ricerca-
sostituzione
% corrisponde a "1,$", cioè:
:%s/a/b/
sostituirà la prima occorrenza di
'a' con 'b' attraverso tutto il file
Alcuni simboli speciali includono:
& propriamente, la parola chiave
ricercata
Esempio:
:s/tr/&ace
sostituisce 'tr' con 'trace'
\U trasforma in lettere maiuscole ciò
che lo segue
Esempio:
:s/case/\U&/
cambia 'case' in 'CASE'
\u trasforma in maiuscolo solamente
il primo carattere
\L converte in lettere minuscole
\l converte in minuscolo solamente
il primo carattere
ESEMPI DI RICERCHE GLOBALI
Con i comandi EX abbiamo già visto come sia possibile effettuare
delle ricerche globali, che agiscono sull'intero file editato.
:g/bad/d cancella tutte le linee che
contengono la stringa 'bad'
:g/bad/p stampa tutte le linee che
contengono la stringa 'bad'
:g/bad/co $ copia tutte le linee che
contengono la stringa 'bad'
alla fine del file (per
invertire il comando, e
quindi aggiungerle all'inizio
del file, lanciare il comando
con '1' invece di '$')
:g/hello/ y"A esegue uno YANK di tutte le
occorrenze di 'hello' nel
buffer con nome 'a'.
È importante notare
la lettera maiuscola nel
nome del buffer; se viene
utilizzata la lettera
minuscola, dopo aver
eseguito il comando nel
buffer esisterà
solamente l'ultima
occorrenza della parola