Seu problema com o Vim é que você não grok vi .
Você menciona cortar yy
e reclamar que quase nunca deseja cortar linhas inteiras. De fato, os programadores, editando o código-fonte, muitas vezes desejam trabalhar em linhas inteiras, intervalos de linhas e blocos de código. No entanto, yy
é apenas uma das muitas maneiras de puxar o texto para o buffer de cópia anônimo (ou "registrar", como é chamado no vi ).
O "zen" do vi é que você está falando um idioma. A inicial y
é um verbo. A declaração yy
é sinônimo de y_
. O y
dobrou para facilitar a digitação, pois é uma operação tão comum.
Isso também pode ser expresso como dd
P
(exclua a linha atual e cole uma cópia de volta no lugar; deixar uma cópia no registro anônimo como efeito colateral). Os y
e d
"verbos" tomar qualquer movimento como o "sujeito". Assim, yW
é "puxar daqui (o cursor) até o final da palavra atual / seguinte (grande)" e y'a
é "puxar daqui para a linha que contém a marca denominada ' a '".
Se você entender apenas os movimentos básicos do cursor para cima, baixo, esquerda e direita, o vi não será mais produtivo do que uma cópia do "bloco de notas" para você. (Ok, você ainda terá o destaque da sintaxe e a capacidade de lidar com arquivos maiores que uns 45KB ou mais; então trabalhe comigo aqui).
vi possui 26 "marcas" e 26 "registros". Uma marca é definida para qualquer local do cursor usando o m
comando Cada marca é designada por uma única letra minúscula. Assim, ma
define a marca ' a ' para o local atual e mz
define a marca ' z '. Você pode ir para a linha que contém uma marca usando o '
comando (aspas simples). Assim, 'a
move-se para o início da linha que contém a marca ' a '. Você pode ir para o local preciso de qualquer marca usando o `
comando (aspas). Assim `z
, moverá diretamente para o local exato da marca ' z '.
Por serem "movimentos", eles também podem ser usados como sujeitos para outras "declarações".
Portanto, uma maneira de cortar uma seleção arbitrária de texto seria largar uma marca (eu costumo usar ' a ' como minha "primeira marca", ' z ' como minha próxima marca, ' b ' como outra e ' e ' como outro (não me lembro de ter usado interativamente mais de quatro marcas em 15 anos de uso do vi ; cria-se as próprias convenções sobre como as marcas e os registros são usados por macros que não perturbam o contexto interativo). para a outra extremidade do texto desejado; podemos começar em qualquer extremidade, não importa. Em seguida, podemos simplesmente usar d`a
para recortar ou y`a
copiar. Portanto, todo o processo possui cinco pressionamentos de tecla (seis se começamos em "insert"). "modo e necessário paraEscfora do modo de comando). Uma vez que tenhamos cortado ou copiado, em seguida, colando em uma cópia é uma única tecla: p
.
Eu digo que essa é uma maneira de cortar ou copiar texto. No entanto, é apenas um de muitos. Frequentemente, podemos descrever de maneira mais sucinta o intervalo de texto sem mover o cursor e soltar uma marca. Por exemplo, se eu estou em um parágrafo de texto que posso usar {
e }
movimentos para o início ou fim do parágrafo, respectivamente. Então, para mover um parágrafo de texto, eu o cortei usando {
d}
(3 pressionamentos de tecla). (Se já estiver na primeira ou na última linha do parágrafo, posso simplesmente usar d}
ou d{
respectivamente.
A noção de "parágrafo" assume como padrão algo que geralmente é intuitivamente razoável. Assim, muitas vezes funciona tanto para código quanto para prosa.
Freqüentemente conhecemos algum padrão (expressão regular) que marca uma extremidade ou a outra do texto em que estamos interessados. Procurar para frente ou para trás são movimentos no vi . Assim, eles também podem ser usados como "sujeitos" em nossas "declarações". Então, eu posso usar d/foo
para cortar da linha atual para a próxima linha que contém a string "foo" e y?bar
copiar da linha atual para a linha mais recente (anterior) que contém "bar". Se não quiser linhas inteiras, ainda posso usar os movimentos de pesquisa (como declarações próprias), largar minha (s) marca (s) e usar os `x
comandos conforme descrito anteriormente.
Além de "verbos" e "sujeitos", o vi também possui "objetos" (no sentido gramatical do termo). Até agora, descrevi apenas o uso do registro anônimo. No entanto, eu posso usar qualquer um dos 26 registros "nomeados" prefixando a referência "objeto" com "
(o modificador de aspas duplas). Portanto, se eu usar "add
, estou cortando a linha atual no registro ' a ' e, se usar "by/foo
, estou puxando uma cópia do texto daqui para a próxima linha que contém "foo" no registro ' b '. Para colar a partir de um registo I simplesmente prefixar a pasta com a mesma sequência de modificador: "ap
cola uma cópia da ' um ' registo'"bP
cola uma cópia de ' b ' antes da linha atual.
Essa noção de "prefixos" também adiciona os análogos dos "adjetivos" gramaticais e dos "advérbios" à linguagem da "manipulação de texto". A maioria dos comandos (verbos) e movimento (verbos ou objetos, dependendo do contexto) também podem usar prefixos numéricos. 3J
significa "unir as próximas três linhas" e d5}
significa "excluir da linha atual até o final do quinto parágrafo abaixo daqui".
Isso tudo é nível intermediário vi . Nada disso é específico do Vim e existem truques muito mais avançados no vi, se você estiver pronto para aprendê-los. Se você dominar apenas esses conceitos intermediários, provavelmente descobrirá que raramente precisa escrever macros porque a linguagem de manipulação de texto é suficientemente concisa e expressiva para fazer a maioria das coisas com bastante facilidade usando a linguagem "nativa" do editor.
Uma amostra de truques mais avançados:
Existem vários :
comandos, principalmente a :% s/foo/bar/g
técnica de substituição global. (Isso não é avançado, mas outros :
comandos podem ser). Todo o :
conjunto de comandos foi herdado historicamente pelas encarnações anteriores do vi como os utilitários ed (editor de linha) e, posteriormente, o ex (editor de linha estendida). Na verdade, vi é assim chamado porque é a interface visual para ex .
:
comandos normalmente operam sobre linhas de texto. ed e ex foram escritos em uma época em que as telas dos terminais eram incomuns e muitos terminais eram dispositivos "teletype" (TTY). Por isso, era comum trabalhar com cópias impressas do texto, usando comandos por meio de uma interface extremamente concisa (as velocidades de conexão comuns eram de 110 baud ou aproximadamente 11 caracteres por segundo - o que é mais lento que um datilógrafo rápido; sessões interativas para vários usuários; além disso, muitas vezes havia alguma motivação para economizar papel).
Portanto, a sintaxe da maioria dos :
comandos inclui um endereço ou intervalo de endereços (número da linha) seguido por um comando. Naturalmente, pode-se usar números de linhas literais: :127,215 s/foo/bar
para alterar a primeira ocorrência de "foo" em "bar" em cada linha entre 127 e 215. Também se pode usar algumas abreviações como .
ou $
para as linhas atuais e últimas, respectivamente. Também se pode usar prefixos relativos +
e -
se referir a compensações antes ou antes da linha atual, respectivamente. Assim: :.,$j
significando "da linha atual até a última linha, junte todos eles em uma linha". :%
é sinônimo de :1,$
(todas as linhas).
Os comandos :... g
e :... v
dão algumas explicações, pois são incrivelmente poderosos. :... g
é um prefixo para "globalmente" aplicar um comando subseqüente a todas as linhas que correspondem a um padrão (expressão regular) enquanto :... v
aplica esse comando a todas as linhas que NÃO correspondem ao padrão especificado ("v" de "conVerse"). Como com outros comandos ex, estes podem ser prefixados por referências de endereçamento / intervalo. Assim, :.,+21g/foo/d
significa "excluir quaisquer linhas que contenham a string" foo "da atual até as próximas 21 linhas" enquanto :.,$v/bar/d
significa "daqui até o final do arquivo, exclua quaisquer linhas que NÃO contenham a string" bar ".
É interessante que o comando comum do Unix grep foi realmente inspirado por este comando ex (e é nomeado após a maneira como foi documentado). O comando ex:g/re/p
(grep) foi a maneira como eles documentaram como "globalmente" "imprimir" linhas contendo uma "expressão regular" (re). Quando ed e ex foram usados, o :p
comando foi um dos primeiros que alguém aprendeu e, geralmente, o primeiro usado ao editar qualquer arquivo. Foi assim que você imprimiu o conteúdo atual (geralmente apenas uma página cheia de cada vez usando :.,+25p
ou algo parecido).
Observe que :% g/.../d
ou (sua contraparte inversa / inversa: :% v/.../d
são os padrões de uso mais comuns. No entanto, existem alguns outros ex
comandos que vale a pena lembrar:
Podemos usar m
para mover linhas e j
unir linhas. Por exemplo, se você tem uma lista e deseja separar todos os itens correspondentes (ou inversamente NÃO correspondentes a algum padrão) sem excluí-los, pode usar algo como: :% g/foo/m$
... e todas as linhas "foo" serão movidas para o final do arquivo. (Observe a outra dica sobre como usar o final do seu arquivo como um espaço temporário). Isso preservará a ordem relativa de todas as linhas "foo" e as extrairá do restante da lista. (Isso seria equivalente a fazer algo como: 1G!GGmap!Ggrep foo<ENTER>1G:1,'a g/foo'/d
(copie o arquivo para sua própria cauda, filtre a cauda grep
e exclua todas as coisas da cabeça).
Para unir linhas normalmente, posso encontrar um padrão para todas as linhas que precisam ser unidas ao seu antecessor (todas as linhas que começam com "^" em vez de "^ *" em uma lista de marcadores, por exemplo). Nesse caso, eu usaria: :% g/^ /-1j
(para cada linha correspondente, suba uma linha e junte-se a elas). (BTW: para listas de bala tentando procurar as linhas de bala e juntar-se para a próxima não funciona para algumas razões ... ele pode se juntar a uma linha de bala para outro, e não vai aderir a qualquer linha de bala para todos de suas continuações; funcionará apenas em pares nas partidas).
Quase desnecessário mencionar que você pode usar nosso velho amigo s
(substituto) com os comandos g
e v
(global / converse-global). Normalmente você não precisa fazer isso. No entanto, considere alguns casos em que você deseja executar uma substituição apenas em linhas que correspondam a algum outro padrão. Freqüentemente, você pode usar um padrão complicado com capturas e usar referências anteriores para preservar as partes das linhas que você NÃO deseja alterar. No entanto, muitas vezes será mais fácil separar a partida da substituição: :% g/foo/s/bar/zzz/g
- para cada linha que contém "foo" substitua todas as "barras" por "zzz". (Algo como:% s/\(.*foo.*\)bar\(.*\)/\1zzz\2/g
funcionaria apenas para os casos aquelas instâncias de "bar" que foram PRECEDIDAS por "foo" na mesma linha; já é desajeitado o suficiente e precisaria ser distorcido para capturar todos os casos em que "bar" precedeu "foo")
O ponto é que há mais do que apenas p
, s
e d
linhas no ex
conjunto de comandos.
Os :
endereços também podem se referir a marcas. Assim, você pode usar: :'a,'bg/foo/j
para unir qualquer linha que contenha a string foo à sua linha subseqüente, se estiver entre as linhas entre as marcas ' a ' e ' b '. (Sim, todos os ex
exemplos de comandos anteriores podem ser limitados a subconjuntos das linhas do arquivo prefixando esses tipos de expressões de endereçamento).
Isso é bastante obscuro (eu só usei algo assim algumas vezes nos últimos 15 anos). No entanto, admitirei livremente que muitas vezes fiz coisas de forma interativa e interativa que provavelmente poderiam ter sido feitas com mais eficiência se eu tivesse tempo para pensar no encantamento correto.
Outro comando vi ou ex muito útil é :r
ler o conteúdo de outro arquivo. Assim: :r foo
insere o conteúdo do arquivo chamado "foo" na linha atual.
Mais poderoso é o :r!
comando. Isso lê os resultados de um comando. É o mesmo que suspender a sessão do vi , executar um comando, redirecionar sua saída para um arquivo temporário, retomar a sua sessão do vi e ler o conteúdo do temp. Arquivo.
Ainda mais poderosos são os comandos !
(bang) e :... !
( ex bang). Eles também executam comandos externos e lêem os resultados no texto atual. No entanto, eles também filtram seleções do nosso texto através do comando! Podemos ordenar todas as linhas em nosso arquivo 1G!Gsort
( G
é o comando vi "goto"; o padrão é ir para a última linha do arquivo, mas pode ser prefixado por um número de linha, como 1, a primeira linha). Isso é equivalente à variante ex:1,$!sort
. Os escritores costumam usar !
os utilitários Unix fmt ou fold para reformatar ou "agrupar palavras" seleções de texto. Uma macro muito comum é{!}fmt
(reformate o parágrafo atual). Às vezes, os programadores o usam para executar seu código, ou apenas partes dele, por meio de recuo ou outras ferramentas de reformatação de código.
Usar os comandos :r!
e !
significa que qualquer utilitário ou filtro externo pode ser tratado como uma extensão do nosso editor. Ocasionalmente, eu os usei com scripts que extraíam dados de um banco de dados ou com comandos wget ou lynx que extraíram dados de um site ou comandos ssh que extraíram dados de sistemas remotos.
Outro comando ex útil é :so
(abreviação de :source
). Isso lê o conteúdo de um arquivo como uma série de comandos. Quando você começar a vi normalmente, implicitamente, realiza uma :source
em ~/.exinitrc
arquivo (e Vim normalmente faz isso em ~/.vimrc
, naturalmente). O uso disso é que você pode alterar o perfil do editor em tempo real, fornecendo simplesmente um novo conjunto de macros, abreviações e configurações do editor. Se você é sorrateiro, pode até usar isso como um truque para armazenar sequências de comandos de edição ex para aplicar a arquivos sob demanda.
Por exemplo, eu tenho um arquivo de sete linhas (36 caracteres) que executa um arquivo no wc e insere um comentário no estilo C na parte superior do arquivo que contém esses dados de contagem de palavras. Posso aplicar essa "macro" a um arquivo usando um comando como:vim +'so mymacro.ex' ./mytarget
(A +
opção de linha de comando para vi e Vim é normalmente usada para iniciar a sessão de edição em um determinado número de linha. No entanto, é um fato pouco conhecido que se pode seguir +
qualquer expressão / comando ex válido , como um comando "source" como Eu fiz aqui; para um exemplo simples, tenho scripts que invocam: vi +'/foo/d|wq!' ~/.ssh/known_hosts
para remover uma entrada do meu arquivo de hosts conhecidos SSH de maneira não interativa enquanto estou reinventando um conjunto de servidores).
Geralmente é muito mais fácil escrever essas "macros" usando Perl, AWK, sed (que é, de fato, como grep um utilitário inspirado no comando ed ).
O @
comando é provavelmente o comando vi mais obscuro . Ocasionalmente, ministrando cursos avançados de administração de sistemas por quase uma década, conheci muito poucas pessoas que já o usaram. @
executa o conteúdo de um registro como se fosse um comando vi ou ex .
Exemplo: Costumo usar: :r!locate ...
para encontrar algum arquivo no meu sistema e ler seu nome no meu documento. A partir daí, excluo quaisquer ocorrências estranhas, deixando apenas o caminho completo para o arquivo em que estou interessado. Em vez de trabalhar Tabminuciosamente em cada componente do caminho (ou pior, se estiver preso em uma máquina sem o suporte à conclusão da guia em sua cópia do vi ) eu apenas uso:
0i:r
(para transformar a linha atual em um comando válido : r ),
"cdd
(para excluir a linha no registro "c") e
@c
execute esse comando.
São apenas 10 pressionamentos de tecla (e a expressão "cdd
@c
é efetivamente uma macro de dedo para mim, para que eu possa digitá-la quase tão rapidamente quanto qualquer palavra comum de seis letras).
Um pensamento sóbrio
Eu apenas arranhei a superfície do poder do vi e nada do que descrevi aqui faz parte das "melhorias" para as quais o vim é nomeado! Tudo o que descrevi aqui deve funcionar em qualquer cópia antiga do vi de 20 ou 30 anos atrás.
Existem pessoas que usaram consideravelmente mais o poder do vi do que eu jamais usarei.