Comentando várias linhas de código, especificadas por números de linha, usando vi ou vim

20

Aprendi com essa pergunta de estouro de pilha que é possível usar vi/ vimcomentar um intervalo especificado de números de linha. Por exemplo, suponha que eu tenha o seguinte script bash:

#!/bin/bash

This
is
my
very
very
great
script

Agora suponha que eu quero comentar os números de linha 6 a 8 (que contêm as palavras very, verye great) usando o #comentário do personagem. Em vi/ vim, posso simplesmente digitar :6,8s/^/#para obter o seguinte:

#!/bin/bash

This
is
my
#very
#very
#great
script

que comenta as linhas 6 a 8.

Minha pergunta é: é possível digitar um liner semelhante que remova o #caractere de comentário das linhas 6 a 8 (mas não outras linhas comentadas no arquivo)?

Dito isto, percebo que há algum debate sobre se estou realmente usando viou vim. Na prática, eu abrir um arquivo script.shcom o comando vi script.sh. Além disso, quando eu digito o comando which vi, eu obtenho /usr/bin/vi. No entanto, quando simplesmente digito vie pressiono Enter, obtenho o seguinte:

~                              VIM - Vi IMproved
~
~                               version 7.2.330
~                           by Bram Moolenaar et al.
~                 Vim is open source and freely distributable
~
~                           Sponsor Vim development!
~                type  :help sponsor<Enter>    for information
~
~                type  :q<Enter>               to exit
~                type  :help<Enter>  or  <F1>  for on-line help
~                type  :help version7<Enter>   for version info

o que parece sugerir que eu estou realmente usando vim. Estou acessando um cluster remoto do Ubuntu Linux usando SSH do meu PC. Não estou usando uma GUI do Ubuntu Linux.

Andrew
fonte

Respostas:

22

Você pode usar:

:6,8s/^#//

Mas muito mais fácil é usar o modo de seleção Bloquear visual: Vá para o início da linha 6, pressione Ctrl-v, desça para a linha 8 e pressione x.

Há também o plugin "The NERD Commenter" .

jofel
fonte
2
NERD Commenteré o caminho a percorrer aqui na minha opinião! +1 para isso
user1146332 30/07/2013
7

Sei que sua pergunta especifica o uso de viou, vimmas aqui estão algumas outras opções para fazer isso sem precisar abrir o arquivo manualmente:

  • Perl

    perl -ne 'if($. <=8 && $. >= 6){s/^\s*#//;}print' foo.sh 
    
  • Versão Perl> = 5.10

    perl -ne '$. ~~ [6..8] && s/^\s*#//;print' foo.sh 
    

    Isso imprimirá o conteúdo do arquivo, você pode redirecionar para outro ( > new_file.sh) ou usar ipara editar o arquivo no local:

    perl -i -ne '$. ~~ [6..8] && s/^\s*#//;print' foo.sh 
    
  • sed

    sed '6,8 s/^ *#//' foo.sh
    

    Novamente, para fazer isso editar o arquivo original, use i:

    sed -i '6,8 s/^ *#//' foo.sh
    
  • awk/ gawketc:

    gawk '(NR<=8 && NR>= 6){sub("^ *#","")}{print}' foo.sh
    
  • Puro bash:

    c=1; while read line; do 
      if [ $c -ge 6 ] && [ $c -le 8 ]; then 
         echo "${line/\#/}"
      else 
         echo $line 
      fi
      let c++; done < foo.sh
    
terdon
fonte
11
Não se trata tanto de "ter que abrir manualmente o arquivo", porque geralmente você decide quais linhas comentar na inspeção visual durante a edição :) Mas com certeza, é uma boa resposta para a integridade.
Paulo Almeida
2
@PauloAlmeida você está certo, é claro. Eu apenas pensei que poderia ser útil, pois o OP já conhece os números de linha (por causa do primeiro comando usado para comentá-los) e, em qualquer caso, as ferramentas que mostro podem ser aplicadas a uma variedade de problemas.
terdon
4

vié um link simbólico para a vimmaioria das distribuições GNU / Linux, então você está realmente usando vimquando digita vi.

Para remover os comentários, você pode digitar: :6,8s/^#//ou :6,8s/^\s*#//descartar algum espaço à esquerda antes do # símbolo.

lgeorget
fonte
11
Muito obrigado. Parece que pode haver erros de digitação. Talvez devesse ser :6,8s/^#//e 6,8s/^\s*#//?
30813 Andrew
3

Você provavelmente está usando vim.tiny. De qualquer forma, você pode remover os comentários iniciais com:

:6,8s/^#//

Obviamente, se você os inserir de uma maneira diferente (por exemplo, com um espaço extra), poderá ser necessário remover o que estiver lá. Com o vim completo, selecionar visualmente colunas e inserir / excluir caracteres é uma maneira mais fácil de fazer a mesma coisa.

Paulo Almeida
fonte
3

Pessoalmente, minha maneira favorita é usar o modo de bloqueio visual

ctrl+ vpara entrar no modo de bloqueio visual, use as teclas de seta ou hjkl para selecionar as linhas e pressione xou del.

Quer eles de volta?

ctrl+ vfaça a seleção e depois I(capital i)#Esc

exussum
fonte
3

Atualmente, o AFAIK, vi é um link simbólico do vim (tente which viou type visiga os links simbólicos). Talvez até /usr/bin/vi-> /etc/alternatives/vi-> /usr/bin/vim.basic.

Pessoalmente, para remover várias linhas de comentário, prefiro selecionar um bloco vertical CtrlVe excluí-lo. Se você precisa adicionar um comentário símbolo para várias linhas, você poderia CtrlV, então ShiftI, digite #e Esc, e um comentário será adicionado a várias linhas.

Boris Burkov
fonte
2

As respostas acima, usando

:6,8s/^#//

são uma solução perfeita, mas um pouco complicada de digitar. Isso pode ser simplificado definindo novos comandos no ~/.vimrc.

command -range=% C :<line1>,<line2>s/^/#/
command -range=% D :<line1>,<line2>s/^#//

E você pode apenas digitar

:6,8C
:6,8D

para colocar / excluir o comando.

Se você gosta do modo visual, pode definir mapas

map <F7> :s/^/#/<CR>
map <F8> :s/^#//<CR>

Como tal, você só precisa selecionar um intervalo de linhas no modo visual e pressionar F7e F8para colocar e remover comentários, respectivamente.

Bernhard
fonte
1

Existe esse plugin de mudança de vida tpopechamadovim-commentary

https://github.com/tpope/vim-commentary

Este plugin fornece :

  • Sanidade
  • Comentários devidamente recuados
  • Não comenta linhas vazias / desnecessárias

Uso :

  • Instale via Vundle (ou Pathogen, eu acho).
  • Destaque seu texto e pressione, :que será exibido como:<,'>
  • Digite Comentário aqui :<,'>Commentarye pressione Enter.
  • Bom. Seu broto feito.
Weston Ganger
fonte
1

Esta resposta está aqui para 1) mostram o código correto para colar em uma .vimrcpara conseguir vim 7.4+fazer bloco comentando / descomentando mantendo nível de recuo com um atalho no modo visual e 2) para explicá-lo.

Aqui está o código:

let b:commentChar='//'
autocmd BufNewFile,BufReadPost *.[ch]    let b:commentChar='//'
autocmd BufNewFile,BufReadPost *.cpp    let b:commentChar='//'
autocmd BufNewFile,BufReadPost *.py    let b:commentChar='#'
autocmd BufNewFile,BufReadPost *.*sh    let b:commentChar='#'
function! Docomment ()
  "make comments on all the lines we've grabbed
  execute '''<,''>s/^\s*/&'.escape(b:commentChar, '\/').' /e'
endfunction
function! Uncomment ()
  "uncomment on all our lines
  execute '''<,''>s/\v(^\s*)'.escape(b:commentChar, '\/').'\v\s*/\1/e'
endfunction
function! Comment ()
  "does the first line begin with a comment?
  let l:line=getpos("'<")[1]
  "if there's a match
  if match(getline(l:line), '^\s*'.b:commentChar)>-1
    call Uncomment()
  else
    call Docomment()
  endif
endfunction
vnoremap <silent> <C-r> :<C-u>call Comment()<cr><cr>

Como funciona:

  • let b:commentChar='//': Isso cria uma variável no vim. o baqui refere-se ao âmbito de aplicação, que neste caso está contido no tampão, o que significa que o ficheiro que está aberto. Os caracteres do seu comentário são cadeias de caracteres e precisam ser colocados entre aspas; as aspas não fazem parte do que será substituído ao alternar os comentários.

  • autocmd BufNewFile,BufReadPost *...: Os comandos automáticos são acionados de diferentes maneiras; nesse caso, eles são acionados quando um novo arquivo ou o arquivo lido termina com uma certa extensão. Uma vez acionado, execute o seguinte comando, o que nos permite alterar o commentChartipo de arquivo dependendo. Existem outras maneiras de fazer isso, mas elas são mais confusas para iniciantes (como eu).

  • function! Docomment(): As funções são declaradas iniciando functione terminando com endfunction. As funções devem começar com uma capital. os !garante que esta função substitui qualquer funções anteriores como definidos Docomment()com esta versão Docomment(). Sem o !, tive erros, mas isso pode ser porque eu estava definindo novas funções através da linha de comando do vim.

  • execute '''<,''>s/^\s*/&'.escape(b:commentChar, '\/').' /e': Executar chama um comando. Nesse caso, estamos executando substitute, o que pode assumir um intervalo (por padrão, esta é a linha atual), como %para todo o buffer ou '<,'>para a seção destacada. ^\s*é regex para corresponder ao início de uma linha seguida por qualquer quantidade de espaço em branco, que é então anexado a (devido a &). O .aqui é usado para concatenação de cadeias, pois escape()não pode ser colocado entre aspas. escape()permite que você escape um caractere commentCharque corresponda aos argumentos (nesse caso, \e /), acrescentando-os com a \. Depois disso, concatenamos novamente com o final da nossa substitutestring, que tem oebandeira. Essa bandeira nos deixa falhar silenciosamente, o que significa que, se não encontrarmos uma correspondência em uma determinada linha, não gritaremos sobre isso. Como um todo, essa linha nos permite colocar um caractere de comentário seguido por um espaço antes do primeiro texto, o que significa que mantemos nosso nível de indentação.

  • execute '''<,''>s/\v(^\s*)'.escape(b:commentChar, '\/').'\v\s*/\1/e': Isso é semelhante ao nosso último grande e longo comando. Exclusivo para este, temos \v, o que garante que não temos que escapar do nosso (), e 1, que se refere ao grupo que fizemos com o nosso (). Basicamente, estamos combinando uma linha que começa com qualquer quantidade de espaço em branco e, em seguida, nosso caractere de comentário seguido por qualquer quantidade de espaço em branco, e estamos mantendo apenas o primeiro conjunto de espaços em branco. Novamente, evamos falhar silenciosamente se não tivermos um caractere de comentário nessa linha.

  • let l:line=getpos("'<")[1]: define uma variável como fizemos com o nosso caractere de comentário, mas lrefere-se ao escopo local (local para esta função). getpos()obtém a posição de, nesse caso, o início de nosso destaque e os [1]meios que nos importam apenas com o número da linha, e não com outras coisas como o número da coluna.

  • if match(getline(l:line), '^\s*'.b:commentChar)>-1: você sabe como iffunciona. match()verifica se a primeira coisa contém a segunda, então pegamos a linha na qual começamos o destaque e verificamos se ela começa com espaço em branco seguido pelo caractere de comentário. match()retorna o índice onde isso é verdade e -1se nenhuma correspondência foi encontrada. Como ifavalia todos os números diferentes de zero como verdadeiros, precisamos comparar nossa saída para ver se é maior que -1. Comparação nos vimretornos 0 se falso e 1 se verdadeiro, que é o que ifdeseja ver para avaliar corretamente.

  • vnoremap <silent> <C-r> :<C-u>call Comment()<cr><cr>: vnoremapsignifica mapear o seguinte comando no modo visual, mas não o mapeie recursivamente (ou seja, não altere nenhum outro comando que possa ser usado de outras maneiras). Basicamente, se você é um novato em vim, sempre use noremappara se certificar de não quebrar as coisas. <silent>significa "Não quero suas palavras, apenas suas ações" e diz para não imprimir nada na linha de comando. <C-r>é o que estamos mapeando, que é ctrl + r nesse caso (observe que você ainda pode usar Cr normalmente para "refazer" no modo normal com esse mapeamento). C-ué meio confuso, mas basicamente garante que você não perca o realce visual (de acordo com esta resposta , o comando começa com '<,'>o que queremos).callaqui apenas diz ao vim para executar a função que chamamos e <cr>refere-se a pressionar o enterbotão. Temos que apertar uma vez para realmente chamar a função (caso contrário, apenas digitamos call function()na linha de comando, e temos que apertá-la novamente para que nossos substitutos passem por todo o caminho (não sei ao certo por que, mas tanto faz).

Enfim, espero que isso ajude. Isso vai levar nada destacou com v, Vou C-v, cheque se a primeira linha é comentada, se sim, tentar tire todas as linhas destacadas, e se não, adicionar uma camada extra de caracteres de comentário para cada linha. Este é o meu comportamento desejado; Eu não queria apenas alternar se cada linha do bloco era comentada ou não, por isso funciona perfeitamente para mim depois de fazer várias perguntas sobre o assunto.

jeremysprofile
fonte