Il tuo problema con Vim è che non si Grok VI .
Citi di tagliare yy
e lamentarti del fatto che non vuoi quasi mai tagliare intere linee. In effetti i programmatori, modificando il codice sorgente, molto spesso vogliono lavorare su intere linee, intervalli di linee e blocchi di codice. Tuttavia, yy
è solo uno dei molti modi per trascinare il testo nel buffer della copia anonima (o "registra" come viene chiamato in vi ).
Lo "Zen" di vi è che stai parlando una lingua. L'iniziale y
è un verbo. La dichiarazione yy
è sinonimo di y_
. La y
raddoppia fino a rendere facile digitare, dato che è un'operazione così comune.
Questo può anche essere espresso come dd
P
(eliminare la riga corrente e incollare una copia in posizione; lasciando una copia nel registro anonimo come effetto collaterale). Le y
e d
"verbi" prendere qualsiasi movimento come loro "soggetto". Quindi yW
è "yank da qui (il cursore) fino alla fine della parola corrente / successiva (grande)" ed y'a
è "yank da qui alla linea contenente il segno denominato" a ".
Se capisci solo i movimenti di base del cursore su, giù, sinistra e destra, allora vi non sarà più produttivo di una copia di "blocco note" per te. (Va bene, avrai comunque l'evidenziazione della sintassi e la possibilità di gestire file più grandi di un arbusto di ~ 45 KB o giù di lì; ma lavora con me qui).
vi ha 26 "marchi" e 26 "registri". Un segno è impostato su qualsiasi posizione del cursore usando il m
comando. Ogni segno è indicato da una singola lettera minuscola. Così ma
imposta il ' un ' mark to la posizione corrente, e mz
imposta la ' z mark'. È possibile passare alla riga contenente un segno utilizzando il '
comando (virgoletta singola). Quindi si 'a
sposta all'inizio della riga contenente il segno " a ". È possibile spostarsi nella posizione precisa di qualsiasi segno utilizzando il `
comando (backquote). Quindi `z
si sposterà direttamente nella posizione esatta del segno ' z '.
Poiché questi sono "movimenti", possono anche essere usati come soggetti per altre "dichiarazioni".
Quindi, un modo per tagliare una selezione arbitraria di testo sarebbe quello di rilasciare un segno (di solito uso ' a ' come il mio "primo" segno, ' z ' come il mio segno successivo, ' b ' come un altro e ' e ' come ancora un altro (non ricordo di aver mai usato in modo interattivo più di quattro marchi in 15 anni di utilizzo di vi ; uno crea le proprie convenzioni su come i segni e i registri vengono utilizzati dalle macro che non disturbano il contesto interattivo). all'altro capo del testo desiderato; possiamo iniziare da entrambe le parti, non importa. Quindi possiamo semplicemente usare d`a
per tagliare o y`a
copiare. Quindi l'intero processo ha un overhead di 5 tasti (sei se abbiamo iniziato in "inserisci "modalità e necessarioEscmodalità comando fuori). Una volta che abbiamo tagliato o copiato poi incollare in una copia è un solo tasto: p
.
Dico che questo è un modo per tagliare o copiare il testo. Tuttavia, è solo uno dei tanti. Spesso possiamo descrivere in modo più succinto l'intervallo di testo senza spostare il cursore e rilasciare un segno. Ad esempio, se mi trovo in un paragrafo di testo, posso usare {
e }
spostare rispettivamente all'inizio o alla fine del paragrafo. Quindi, per spostare un paragrafo di testo, lo taglio usando {
d}
(3 battute). (Se mi capita di trovarmi già nella prima o nell'ultima riga del paragrafo, posso semplicemente usare d}
o d{
rispettivamente.
La nozione di "paragrafo" assume come impostazione predefinita qualcosa che di solito è intuitivamente ragionevole. Quindi funziona spesso sia per il codice che per la prosa.
Spesso conosciamo qualche modello (espressione regolare) che segna un'estremità o l'altra del testo a cui siamo interessati. La ricerca in avanti o all'indietro sono movimenti in vi . Quindi possono anche essere usati come "soggetti" nelle nostre "dichiarazioni". Quindi posso usare d/foo
per tagliare dalla riga corrente alla riga successiva contenente la stringa "pippo" e y?bar
per copiare dalla riga corrente alla riga (precedente) più recente contenente "barra". Se non desidero linee intere, posso comunque usare i movimenti di ricerca (come loro dichiarazioni), rilasciare i miei segni e usare i `x
comandi come descritto in precedenza.
Oltre ai "verbi" e ai "soggetti" vi hanno anche "oggetti" (nel senso grammaticale del termine). Finora ho descritto solo l'uso del registro anonimo. Tuttavia, posso usare uno qualsiasi dei 26 registri "nominati" prefissando il riferimento "oggetto" con "
(il modificatore di virgolette doppie). Quindi se uso "add
sto tagliando la riga corrente nel registro ' a ' e se uso, "by/foo
sto tirando una copia del testo da qui alla riga successiva contenente "pippo" nel registro ' b '. Per incollare da un registro ho semplicemente il prefisso incolla con la stessa sequenza di modifica: "ap
incolla una copia del ' a ' registro '"bP
incolla una copia da ' b ' a prima della riga corrente.
Questa nozione di "prefissi" aggiunge anche gli analoghi di "aggettivi" grammaticali e "avverbi" al nostro linguaggio "manipolazione del testo". La maggior parte dei comandi (verbi) e del movimento (verbi o oggetti, a seconda del contesto) possono anche assumere prefissi numerici. 3J
significa "unisci le tre righe successive" e d5}
significa "elimina dalla riga corrente fino alla fine del quinto paragrafo in basso da qui".
Questo è tutto livello intermedio vi . Niente di tutto questo è specifico di Vim e ci sono trucchi molto più avanzati in vi se sei pronto per impararli. Se dovessi padroneggiare solo questi concetti intermedi, probabilmente scoprirai che raramente hai bisogno di scrivere macro perché il linguaggio di manipolazione del testo è sufficientemente conciso ed espressivo per fare la maggior parte delle cose abbastanza facilmente usando il linguaggio "nativo" dell'editor.
Un campione di trucchi più avanzati:
Esistono numerosi :
comandi, in particolare la :% s/foo/bar/g
tecnica di sostituzione globale. (Non è avanzato ma :
possono esserci altri comandi). L'intero :
set di comandi è stata storicamente ereditata dal VI 's precedenti incarnazioni come la cura (line) e successivamente le ex utenze (line estesa). In realtà vi è così chiamato perché è l'interfaccia visiva di ex .
:
i comandi normalmente operano su righe di testo. ed e ex stati scritti in un'epoca in cui gli schermi terminali sono rari e molti terminali erano dispositivi "telescriventi" (TTY). Quindi era comune lavorare da copie stampate del testo, usando i comandi attraverso un'interfaccia estremamente concisa (le velocità di connessione comuni erano 110 baud o, approssimativamente, 11 caratteri al secondo - che è più lento di una dattilografa veloce; i ritardi erano comuni su sessioni interattive multiutente; inoltre c'era spesso qualche motivazione per conservare la carta).
Quindi la sintassi della maggior parte dei :
comandi include un indirizzo o un intervallo di indirizzi (numero di riga) seguito da un comando. Naturalmente si potrebbero usare i numeri di riga letterali: :127,215 s/foo/bar
per cambiare la prima occorrenza di "pippo" in "barra" su ogni riga tra 127 e 215. Si potrebbero anche usare alcune abbreviazioni come .
o rispettivamente $
per le righe correnti e ultime. Si potrebbero anche usare prefissi relativi +
e -
fare riferimento agli offset dopo o prima della linea di curvatura, rispettivamente. Quindi: :.,$j
significato "dalla riga corrente all'ultima riga, uniscili tutti in una riga". :%
è sinonimo di :1,$
(tutte le linee).
I comandi :... g
e :... v
portano alcune spiegazioni in quanto sono incredibilmente potenti. :... g
è un prefisso per "globalmente" applicare un comando successivo a tutte le linee che corrispondono a un modello (espressione regolare) mentre :... v
applica tale comando a tutte le linee che NON corrispondono al modello dato ("v" da "conVerse"). Come con altri comandi ex , questi possono essere prefissati indirizzando i riferimenti / intervallo. Quindi :.,+21g/foo/d
significa "elimina tutte le righe contenenti la stringa" pippo "da quella corrente attraverso le 21 successive" mentre :.,$v/bar/d
significa "da qui alla fine del file, elimina tutte le righe che NON contengono la" barra ".
È interessante notare che il comando Unix comune grep in realtà è stato ispirato da questo ex comando (e prende il nome dal modo in cui è stato documentato). Il comando ex:g/re/p
(grep) è stato il modo in cui hanno documentato come "stampare" globalmente le righe contenenti una "espressione regolare" (ri). Quando sono stati usati ed ed ex , il :p
comando è stato uno dei primi che qualcuno ha imparato e spesso il primo utilizzato durante la modifica di qualsiasi file. È stato il modo in cui hai stampato i contenuti attuali (di solito solo una pagina alla volta utilizzando :.,+25p
o alcuni di questi).
Nota che :% g/.../d
o (la sua controparte reVerse / conVerse: :% v/.../d
sono i modelli di utilizzo più comuni. Tuttavia ci sono un paio di altri ex
comandi che vale la pena ricordare:
Possiamo usare m
per spostare le linee e j
unire le linee. Ad esempio, se hai un elenco e desideri separare tutti gli elementi corrispondenti (o viceversa NON abbinare un modello) senza eliminarli, puoi utilizzare qualcosa del tipo: :% g/foo/m$
... e tutte le righe "pippo" saranno state spostate in la fine del file. (Nota l'altro suggerimento sull'uso della fine del file come spazio di lavoro). Ciò avrà preservato l'ordine relativo di tutte le righe "pippo" pur avendo estratto dal resto dell'elenco. (Ciò equivarrebbe a fare qualcosa del tipo: 1G!GGmap!Ggrep foo<ENTER>1G:1,'a g/foo'/d
(copia il file nella sua coda, filtra la coda grep
ed elimina tutte le cose dalla testa).
Per unire le linee di solito posso trovare un modello per tutte le linee che devono essere unite al loro predecessore (tutte le linee che iniziano con "^" anziché "^ *" in alcuni elenchi puntati, per esempio). Per quel caso userei: :% g/^ /-1j
(per ogni riga corrispondente, salgo una riga e unisciti a loro). (BTW: per le liste di proiettile cercando di cercare per le linee di proiettile e unisciti al prossimo non funziona per un paio di ragioni ... può aderire a una linea proiettile ad un altro, e non sarà unirsi a qualsiasi linea proiettile a tutti di le sue continuazioni; funzionerà solo in coppia sulle partite).
Quasi inutile menzionare che puoi usare il nostro vecchio amico s
(sostituto) con i comandi g
e v
(global / converse-global). Di solito non è necessario farlo. Tuttavia, prendere in considerazione alcuni casi in cui si desidera eseguire una sostituzione solo su righe corrispondenti ad altri pattern. Spesso è possibile utilizzare un modello complicato con acquisizioni e utilizzare i riferimenti posteriori per preservare le parti delle linee che NON si desidera modificare. Tuttavia, sarà spesso più semplice separare la corrispondenza dalla sostituzione: :% g/foo/s/bar/zzz/g
- per ogni riga contenente "pippo" sostituisci tutte le "barre" con "zzz". (Qualcosa di simile a:% s/\(.*foo.*\)bar\(.*\)/\1zzz\2/g
funzionerebbe solo per i casi in cui le istanze di "bar" sono state PRECEDATE da "pippo" sulla stessa riga; è già abbastanza sgraziato e dovrebbe essere ulteriormente modificato per catturare tutti i casi in cui "bar" ha preceduto "foo")
Il punto è che ci sono più di semplici p
, s
e d
righe nel ex
set di comandi.
Gli :
indirizzi possono anche riferirsi a segni. Quindi puoi usare: :'a,'bg/foo/j
per unire qualsiasi linea contenente la stringa foo alla sua linea successiva, se si trova tra le linee tra i segni ' a ' e ' b '. (Sì, tutti i precedenti ex
esempi di comandi possono essere limitati a sottoinsiemi delle righe del file con il prefisso con questo tipo di espressioni di indirizzamento).
È piuttosto oscuro (ho usato qualcosa del genere solo poche volte negli ultimi 15 anni). Tuttavia, ammetterò liberamente di aver fatto spesso cose in modo iterativo e interattivo che probabilmente avrebbero potuto essere fatte in modo più efficiente se avessi avuto il tempo di pensare al giusto incantesimo.
Un altro comando vi o ex molto utile è :r
leggere il contenuto di un altro file. Pertanto: :r foo
inserisce il contenuto del file denominato "pippo" nella riga corrente.
Più potente è il :r!
comando. Questo legge i risultati di un comando. È lo stesso che sospendere la sessione vi , eseguire un comando, reindirizzare il suo output su un file temporaneo, riprendere la sessione vi e leggere i contenuti dalla temp. file.
Ancora più potenti sono i comandi !
(bang) e :... !
( ex bang). Eseguono anche comandi esterni e leggono i risultati nel testo corrente. Tuttavia, filtrano anche le selezioni del nostro testo tramite il comando! In questo modo possiamo ordinare tutte le righe nel nostro file usando 1G!Gsort
( G
è il comando vi "goto"; il valore predefinito è andare all'ultima riga del file, ma può essere preceduto da un numero di riga, come 1, la prima riga). Ciò equivale alla variante ex:1,$!sort
. Gli scrittori usano spesso !
con le utility Unix fmt o fold per riformare o "racchiudere in parole" selezioni di testo. Una macro molto comune è{!}fmt
(riformatta il paragrafo corrente). I programmatori a volte lo usano per eseguire il loro codice, o solo parti di esso, attraverso rientri o altri strumenti di riformattazione del codice.
L'uso dei comandi :r!
e !
significa che qualsiasi utility o filtro esterno può essere trattato come un'estensione del nostro editor. Di tanto in tanto li ho usati con script che estraevano dati da un database o con comandi wget o lynx che estraevano dati da un sito Web o comandi ssh che estraevano dati da sistemi remoti.
Un altro ex utile comando è :so
(abbreviazione di :source
). Questo legge il contenuto di un file come una serie di comandi. Quando si avvia vi normalmente, implicitamente, esegue una :source
su ~/.exinitrc
file (e Vim solito fa questo su ~/.vimrc
, abbastanza naturalmente). L'uso di questo è che puoi cambiare il tuo profilo dell'editor al volo semplicemente acquistando un nuovo set di macro, abbreviazioni e impostazioni dell'editor. Se sei subdolo si può anche usare questo come un trucco per la memorizzazione di sequenze di ex comandi di modifica da applicare ai file su richiesta.
Ad esempio, ho un file di sette righe (36 caratteri) che esegue un file tramite wc e inserisce un commento in stile C nella parte superiore del file contenente i dati di conteggio delle parole. Posso applicare quella "macro" a un file usando un comando come:vim +'so mymacro.ex' ./mytarget
(Il +
opzione della riga di comando per vi e Vim viene normalmente utilizzata per avviare la sessione di modifica in corrispondenza di un determinato numero di riga. Tuttavia è un fatto poco noto che si può seguire il comando +
con qualsiasi comando / espressione ex valido , come un comando "source" come Ho fatto qui; per un semplice esempio ho degli script che invocano: vi +'/foo/d|wq!' ~/.ssh/known_hosts
per rimuovere una voce dal mio file degli host conosciuti SSH in modo non interattivo mentre sto ri-immaginando un set di server).
Di solito è molto più facile scrivere tali "macro" usando Perl, AWK, sed (che è, in effetti, come grep un'utilità ispirata al comando ed ).
Il @
comando è probabilmente il comando vi più oscuro . Nell'insegnare occasionalmente corsi avanzati di amministrazione dei sistemi per quasi un decennio ho incontrato pochissime persone che l'hanno mai usato. @
esegue il contenuto di un registro come se fosse un comando vi o ex .
Esempio: utilizzo spesso: :r!locate ...
per trovare alcuni file sul mio sistema e leggerne il nome nel mio documento. Da lì elimino qualsiasi hit estraneo, lasciando solo il percorso completo del file che mi interessa. Piuttosto che faticosamente Tabpassare attraverso ogni componente del percorso (o peggio, se mi capita di essere bloccato su una macchina senza supporto per il completamento di Tab nella sua copia di vi ) uso solo:
0i:r
(per trasformare la riga corrente in un comando valido : r ),
"cdd
(per eliminare la riga nel registro "c") e
@c
eseguire quel comando.
Sono solo 10 sequenze di tasti (e l'espressione "cdd
@c
è effettivamente una macro per me, quindi posso scriverla quasi altrettanto rapidamente di qualsiasi parola di sei lettere comune).
Un pensiero che fa riflettere
Ho solo graffiato alla superficie del potere di vi e nessuno di ciò che ho descritto qui è anche parte dei "miglioramenti" per i quali vim prende il nome! Tutto ciò che ho descritto qui dovrebbe funzionare su qualsiasi vecchia copia di vi di 20 o 30 anni fa.
Ci sono persone che hanno usato molto più di VI 's potere di quanto io mai.