Pesquise e substitua no vim em linhas específicas

99

Eu posso usar

:5,12s/foo/bar/g

para procurar fooe substituí-lo por barentre as linhas 5 e 12. Como posso fazer isso apenas na linha 5 e 12 (e não nas linhas intermediárias)?

pfnuesel
fonte

Respostas:

78

O Vim tem átomos de expressão regular especiais que correspondem em certas linhas, colunas, etc .; você pode usá-los (possivelmente além do intervalo) para limitar as correspondências:

:5,12s/\(\%5l\|\%12l\)foo/bar/g

Vejo :help /\%l

Ingo Karkat
fonte
8
Uma maneira mais complicada do que eu esperava, mas responde à minha pergunta perfeitamente. Obrigado!
pfnuesel
57

Você pode fazer a substituição na linha 5 e repeti-la com o mínimo de esforço na linha 12:

:5s/foo/bar
:12&

Conforme apontado por Ingo, :&esquece suas bandeiras. Já que você está usando /g, o comando correto seria :&&:

:5s/foo/bar/g
:12&&

Veja :help :&e amigos.

romainl
fonte
10
+1 para colocar o obscuro :&em uso. Se houver sinalizadores ( s/../../g), será necessário usar :&&, no entanto ...
Ingo Karkat
10
@IngoKarkat, para ser justo, acho que \(\%5l\|\%12l\)é mais obscuro do que:&
doubleDown
14

Você sempre pode adicionar um cao final. Isso pedirá confirmação para cada partida.

:5,12s/foo/bar/gc
reitor
fonte
1
Isso pode ser um pesadelo se houver muitas partidas entre as linhas 5 e 12 (tenha em mente que há uma gbandeira em jogo)
doubleDown
1
@doubleDown Esta não é uma solução universal (onde há muitos candidatos possíveis), mas na maioria dos casos você realmente acha que pressionar n5 ou 6 vezes é mais oneroso do que adicionar \(\%5l\|\%12l\)à instrução substituta?
Dean
Acho isso útil, queria mudar todas as outras linhas, teria sido mais rápido do que acabei fazendo.
tiktak
9

Pergunta interessante. Parece que há apenas seleção de intervalo e nenhuma seleção de linha múltipla:

http://vim.wikia.com/wiki/Ranges

No entanto, se você tiver algo especial nas linhas 5 e 12, poderá usar a :goperadora. Se o seu arquivo for assim (números apenas para referência):

 1     line one
 2     line one
 3     line one
 4     line one
 5     enil one
 6     line one
 7     line one
 8     line one
 9     line one
10     line one
11     line one
12     enil one

E você deseja substituir onepor enonas linhas onde há em enilvez de line:

:g/enil/s/one/eno/
eckes
fonte
5
na verdade, isso está supondo muito
doubleDown
1

Você poderia usar ed- um editor de texto orientado a linhas com comandos semelhantes ao vi e vim. Provavelmente é anterior ao vi e vim.

Em um script (usando um documento here que processa a entrada até o marcador EndCommand) seria semelhante a:

ed file <<EndCommands
    5
    s/foo/bar/g
    7
    s/foo/bar/g
    wq
EndCommands

Obviamente, os comandos ed também podem ser usados ​​na linha de comando.

Suspeito
fonte
3
Não vejo vantagem sobre a vimalternativa.
Bernhard
1
E o mesmo pode ser feito com o Vim; os números podem ser colocados antes do :s, mas ainda há a duplicação do :scomando (que a solução de romainl evita).
Ingo Karkat
Minha opinião é que o usuário pode querer selecionar muito mais do que duas linhas para edição. Nesse caso, uma abordagem não interativa poderia ter sido de interesse - o que AFAIK não pode ser feito com o vim.
suspeito de
1
Oh, o Vim pode fazer isso (por exemplo, no modo "Ex"), mas você está certo de que outra ferramenta deve ser preferida a um editor interativo. Minha preferência seria sed, porém ...
Ingo Karkat