:vim — corso in 10 lezioni
Lezione 08 di 10

La riga dei due punti, e il comando :g

Sotto Vim c'è ancora ex, l'editor di riga da cui è nato. Da lì arrivano gli intervalli, i filtri esterni e :g — il comando che fa in un secondo le cose per cui altrove si scrive uno script.

Teoria

:g — «su ogni riga che…, fai questo»

anatomia
:[intervallo]g/pattern/comando

# senza intervallo, l'impostazione è tutto il file
# :g!  oppure  :v  →  agisce sulle righe che NON corrispondono

Funziona in due passate: prima Vim segna tutte le righe che corrispondono al pattern, poi esegue il comando su ciascuna. Questo doppio passaggio è ciò che lo rende sicuro anche quando il comando cancella o sposta righe: l'elenco è già stato deciso.

ComandoEffetto
:g/TODO/dcancella tutte le righe che contengono TODO
:g/^$/delimina le righe vuote
:g/^\s*$/delimina anche quelle con soli spazi
:v/errore/dtiene solo le righe con «errore» — un grep dentro il file
:g/pattern/t$copia in fondo al file tutte le righe che corrispondono
:g/pattern/m0le sposta in cima, in ordine inverso
:g/pattern/-1junisce ogni riga trovata alla precedente
:g/<h2/ .+1,+3s/vecchio/nuovo/gsostituisce solo nelle tre righe dopo ogni <h2
:g/pattern/pstampa le righe: anteprima innocua per verificare il pattern
Prova sempre con p prima. :g/pattern/p elenca in fondo allo schermo le righe che verranno colpite. Se sono quelle giuste, richiami il comando con : e , cambi la p finale in d e vai.

I comandi ex che si combinano con :g

ComandoSignificato
ddelete — cancella
t   (o co)copy — copia dopo la riga indicata
mmove — sposta
jjoin — unisce
ssubstitute — sostituisce
normal tastiesegue quei tasti come se li premessi in NORMAL
>   <indenta / de-indenta

Gli indirizzi si scrivono con . (riga corrente), $ (ultima), 0 (prima dell'inizio), un numero, o uno spostamento relativo come +3 e -1.

Pratica

Far lavorare i programmi esterni dentro Vim

Il punto esclamativo apre una porta verso la shell. Tre forme, tre usi diversi:

FormaEffetto
:!comandoesegue e mostra l'output, senza toccare il file
:r !comandoinserisce l'output nel file, sotto il cursore
:intervallo!comandofiltra quelle righe attraverso il comando e le sostituisce con il risultato
:w !comandomanda il buffer al comando senza salvare (vedi lezione 1)
esempi quotidiani
:%!sort                    # ordina tutto il file
:%!sort -u                 # ordina ed elimina i duplicati
:10,30!sort -t, -k2        # ordina solo quelle righe, per la 2ª colonna
:%!column -t               # incolonna una tabella di testo
:%!python3 -m json.tool     # riformatta un JSON illeggibile
:'<,'>!tr a-z A-Z          # la selezione visuale in maiuscolo
:r !date +\%Y-\%m-\%d      # inserisce la data di oggi
:r !ls *.jpg               # inserisce l'elenco dei file

In NORMAL, l'operatore ! accetta un movimento: !ip sort ordina il paragrafo sotto il cursore, !}sort fino alla riga vuota successiva. Se il risultato non ti piace, u lo annulla come qualsiasi altra modifica.

Attenzione ai caratteri speciali. Nella riga di comando di Vim, % significa «nome del file corrente» e # «file alternativo». Se ti servono letteralmente — per esempio in una stringa di formato di date — vanno protetti con la barra rovescia, come nell'esempio sopra.

Scorciatoie sulla riga di comando

TastoEffetto dopo aver premuto :
↑   ↓scorre lo storico dei comandi filtrato da ciò che hai già scritto
q:apre lo storico come un buffer modificabile: correggi una riga e premi Invio
Ctrl-r Ctrl-winserisce la parola sotto il cursore nel comando
Ctrl-r "inserisce il contenuto del registro innominato
Trucco

:g più macro: il moltiplicatore

Le macro della lezione 5 si eseguono dove sei, e con 999@q vanno avanti finché possono — ma passano anche sulle righe che non c'entrano nulla. :g risolve esattamente questo: seleziona le righe giuste, e su ognuna lancia la macro.

la formula da ricordare
:g/pattern/normal @q
esempio: sistemare solo le righe di configurazione attive
# file di partenza
#max_connections = 100
max_connections = 100
#timeout = 30
timeout = 30
shared_buffers = 128MB

# macro in "q:  A   ;  # rivisto  Esc
# poi:
:g/^[^#]/normal @q

#max_connections = 100
max_connections = 100  ; # rivisto
#timeout = 30
timeout = 30  ; # rivisto
shared_buffers = 128MB  ; # rivisto

Le righe commentate restano intatte, perché il pattern ^[^#] le esclude. La stessa struttura risolve una quantità di problemi reali: applicare una trasformazione complicata solo alle righe di una certa sezione, solo a quelle che contengono un tag, solo a quelle senza un certo campo.

Due varianti che vale la pena conoscere: :g/pattern/normal ct,NUOVO usa direttamente i tasti senza registrare una macro, comodo per modifiche brevi. E :g/pattern/normal! @q con il punto esclamativo ignora le tue mappature personali — più prevedibile se hai un .vimrc ricco.