Buscar y reemplazar en vim en líneas específicas

95

Puedo usar

:5,12s/foo/bar/g

para buscarlo fooy reemplazarlo barentre las líneas 5 y 12. ¿Cómo puedo hacer eso solo en las líneas 5 y 12 (y no en las líneas intermedias)?

pfnuesel
fuente

Respuestas:

76

Vim tiene átomos especiales de expresión regular que coinciden en ciertas líneas, columnas, etc .; puede usarlos (posiblemente además del rango) para limitar las coincidencias:

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

Ver :help /\%l

Ingo Karkat
fuente
8
Una forma más complicada de lo que esperaba pero responde perfectamente a mi pregunta. ¡Gracias!
pfnuesel
56

Puede hacer la sustitución en la línea 5 y repetirla con un mínimo esfuerzo en la línea 12:

:5s/foo/bar
:12&

Como señala Ingo, se :&olvida de sus banderas. Dado que está utilizando /g, el comando correcto sería :&&:

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

Ver :help :&y amigos.

romainl
fuente
10
+1 por :&utilizar lo oscuro . Si hay banderas ( s/../../g), uno tiene que usar :&&, aunque ...
Ingo Karkat
10
@IngoKarkat, para ser justos, creo que \(\%5l\|\%12l\)es más oscuro que:&
doubleDown
13

Siempre puedes agregar un cal final. Esto pedirá confirmación para todos y cada uno de los partidos.

:5,12s/foo/bar/gc
Decano
fuente
1
Esto puede ser una pesadilla si hay muchas coincidencias entre las líneas 5 y 12 (tenga en cuenta que hay una gbandera en juego)
doubleDown
1
@doubleDown Esto no pretende ser una solución universal (donde hay muchos candidatos posibles), pero en la mayoría de los casos, ¿realmente cree que presionar n5 o 6 veces es más oneroso que agregar \(\%5l\|\%12l\)a la declaración sustituta?
Dean
Encuentro esto útil, quería cambiar cada dos líneas, esto habría sido más rápido de lo que terminé haciendo.
tiktak
9

Interesante pregunta. Parece que solo hay selección de rango y no selección de línea múltiple:

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

Sin embargo, si tiene algo especial en las líneas 5 y 12, puede usar el :goperador. Si su archivo se ve así (números solo como referencia):

 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

Y desea reemplazar onepor enoen las líneas donde hay en enillugar de line:

:g/enil/s/one/eno/
eckes
fuente
5
esto en realidad es mucho
doubleDown
1

Podría usar ed: un editor de texto orientado a líneas con comandos similares a vi y vim. Probablemente sea anterior a vi y vim.

En un script (usando un documento aquí que procesa la entrada hasta el marcador EndCommand) se vería así:

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

Obviamente, los comandos ed también se pueden usar en la línea de comandos.

Sospechoso
fuente
3
No veo ninguna ventaja sobre la vimalternativa.
Bernhard
1
Y lo mismo se puede hacer con Vim también; los números se pueden poner antes de :s, pero aún existe la duplicación del :scomando (que evita la solución de romainl).
Ingo Karkat
Mi opinión fue que el usuario podría querer seleccionar mucho más de dos líneas para editar. En ese caso, un enfoque no interactivo podría haber sido de interés, lo que AFAIK no se puede hacer con vim.
sospechoso
1
Oh, Vim puede hacer eso (por ejemplo, en el modo "Ex"), pero tienes razón en que se debería preferir otra herramienta a un editor interactivo. Sin sedembargo, mi preferencia sería ...
Ingo Karkat