Vim: ¿cómo eliminar cada segunda fila?

99

Cómo hacerlo en Vim:

ANTES DE:

aaa
bbb
ccc
ddd
eee
fff

DESPUÉS:

aaa
ccc
eee
descarado
fuente
Debería poder utilizar una macro: oreillynet.com/mac/blog/2006/07/…
Mark Wilkins
Me gusta la gran cantidad de respuestas a esta. Favoreciendo.
froggythefrog

Respuestas:

105

Puedes usar una macro para esto. Haz lo siguiente.

  • Comience en modo comando.
  • Vaya al principio del archivo presionando gg.
  • Presione qq.
  • Haga clic en la flecha hacia abajo y presione dddespués.
  • Presione q.
  • prensa 10000@q

PD: Para ir al modo de comando, simplemente presione Escape un par de veces.

rui
fuente
11
Suponiendo que su archivo tiene menos de 20,000 líneas, por supuesto :-)
paxdiablo
3
En realidad te equivocas Michael. Esto funciona perfectamente ya que VI dejará de ejecutar la macro tan pronto como llegue al final del archivo. Puede probarlo muy fácilmente con el ejemplo anterior.
rui
1
Bueno, como cualquier macro, debe hacerlo bien la primera vez, pero después puede aplicarla a cualquier archivo simplemente escribiendo 10000 @ q. De cualquier manera, creo que es solo una cuestión de gustos, así que definitivamente no voy a iniciar un debate filosófico. :)
rui
3
Prefiero usar 'macro'. Usando macro, usted 'describe' cómo resolvería una tarea en particular y deja que VIM la repita por usted. RUI, preferiría usar 'j' en lugar de la tecla de flecha.
SolutionYogi
4
:g/^/+dfrom user stackoverflow.com/users/254635/ib (abajo) es una forma más elegante de resolver esto.
Sergio Araujo
254

Una forma elegante (y eficiente) de realizar la tarea es invocar el :+deletecomando eliminando la línea que sigue a la actual, en cada línea usando el :globalcomando:

:g/^/+d
ib.
fuente
10
¿Por qué esta respuesta no obtuvo más votos a favor? Esto es tan limpio y simple. Alternativamente, puede eliminar la primera línea y ejecutar el comando anterior para eliminar todas las líneas impares.
Usagi
3
@Usagi: ¡Gracias! Siento lo mismo al respecto. Y sí, tienes toda la razón, :1d|g/^/+dborra las líneas impares.
ib.
@Usagi La otra respuesta fue seleccionada como la 'mejor respuesta' 2 años antes de que apareciera su respuesta. Además, aunque esta es una solución más elegante, podría haberse escrito de una manera más útil (es decir, no se menciona lo que hace ^, mientras que la macro es fácil de entender para cualquiera).
user1271772
3
Lo siento, pero sin una explicación de cómo ese comando realiza el comportamiento deseado, no lo votaría y preferiría la respuesta aceptada, ya que entiendo cómo logra el objetivo. Es la diferencia entre darle un pescado a un hombre y enseñarle a pescar.
Gabe
3
No sé, esta respuesta me hizo salir y aprender a pescar con el comando: g (es decir, me hizo buscar en Google esta página - vim.wikia.com/wiki/Power_of_g ).
snetch
67

Podemos usar :normalo :normpara ejecutar determinados comandos de modo normal. Fuente.

:%norm jdd
Tadhg
fuente
15
Esta respuesta no recibe suficiente atención, posiblemente debido a la falta de explicación tanto aquí como en la hoja de trucos vinculada y desordenada. el comando norm ejecuta los comandos del modo normal equivalentes a las letras que le siguen. Entonces aquí está ejecutando j para moverse hacia abajo en una línea y dd para borrarlo. Esto se puede generalizar a la línea X al agregar más 'j's en este caso.
imoatama
5
y el% es la abreviatura de 1, $ (ejecute el siguiente comando desde la línea 1 hasta el final)
Lambart
3
Me interesa saber por qué %norm ddjno funciona si desea eliminar filas impares.
Cyker
10
:map ^o ddj^o
^o

Aquí ^ significa CTRL. Macro recursiva para eliminar una línea cada dos líneas. Elige bien tu primera línea y listo.

Supercopter Raoul
fuente
8

desde el archivo de correo vim :

:let i=1 | while i <= line('$') | if (i % 2) | exe i . "delete" | endif | let i += 1 | endwhile

(Para escribir en una línea en la línea de comando de vim, eliminará la fila 1,3,5,7, ...)

Fortega
fuente
4
Entonces prefiero !perl -ne 'print unless $. % 2':-)
Alex Brasetvik
Y, Alex, definitivamente preferiría mi solución a la tuya, pero vale la pena considerar esta, ya que es la única solución sensata que usa solo vim aquí.
Michael Krelin - hacker
La forma macro es mucho más fácil.
trusktr
1 debido a la flexibilidad con if (expression)la que también trabaja para cada tercera línea, etc
Jens
5

Siempre puede canalizar a través de un comando de shell, lo que significa que puede usar cualquier lenguaje de scripting que desee:

:%!perl -nle 'print if $. % 2'

(o use "a menos que" en lugar de "si", según las líneas que desee)

Delgado
fuente
No necesita el -lcambio a Perl ... también, yo diría que awkestá un poco más extendido que Perl, aunque en realidad no es mucho más en estos días, y puede hacer esto más corto: :%!awk NR\%2o :%!awk 1-NR\%2para las otras líneas.
Ephemient
4
:%!awk -- '++c\%2'

alternativamente

:%!awk -- 'c++\%2'

dependiendo de la mitad que quieras eliminar.

Michael Krelin - hacker
fuente
Umm, ¿por qué no usar la NRvariable existente ?
Ephemient
Correcto. Porque me olvidé de eso. ;-) Pero en realidad, la variante "adecuada" será aún más larga con NR. Y no habría dos homólogos atractivos .
Michael Krelin - hacker
:%!awk NR\%2o :%!awk 1-NR\%2, como publiqué en otro comentario. Eso es apenas más.
efímero
1
1-NRes más largo que c++. Sí, sé que es un personaje. Como dije, la verdadera razón es que lo olvidé. De todos modos, parece que la gente no aprecia la belleza de awk aquí.
Michael Krelin - hacker
Y NRes más corto que ++c:)
efímero
3

Puede usar las capacidades de búsqueda y sustitución de Vim de esta manera: coloque el cursor en la primera línea y escriba en modo normal:

:.,/fff/s/\n.*\(\n.*\)/\1/g
  • El .,/fff/es el rango para la sustitución. Significa "de esta línea a la línea que coincide con la expresión regular fff(en este caso, la última línea).
  • s///es el comando sustituto. Busca una expresión regular y reemplaza cada aparición de ella con una cadena. El gal final significa repetir la sustitución siempre que se siga encontrando la expresión regular.
  • La expresión regular \n.*\(\n.*\)coincide con una línea nueva, luego una línea completa ( .*coincide con cualquier número de caracteres excepto una línea nueva), luego otra línea nueva y otra línea. Los paréntesis \(y \)hacen que se registre la expresión dentro de ellos, para que podamos usarlo más tarde usando \1.
  • \1 inserta la nueva línea agrupada y la línea posterior de nuevo, porque no queremos que la siguiente línea desaparezca también; solo queremos que el mecanismo de sustitución pase por ella para no eliminarla en el próximo reemplazo.

De esta manera, puede controlar el rango en el que desea que se realice la eliminación y no tiene que usar ninguna herramienta externa.

Daniel Hershcovich
fuente
O en $lugar de /fff/, para el final del archivo, independientemente del contenido del archivo.
efímero
3

Como otro enfoque, también puede usar python si su vim lo admite.

:py import vim; cb = vim.current.buffer; b = cb[:]; cb[:] = b[::2]

b = cb[:]copia temporalmente todas las líneas del búfer actual en b. b[::2]obtiene cada segunda línea del búfer y la asigna a todo el búfer actual cb[:]. La copia en bes necesaria ya que los objetos de búfer no parecen admitir la sintaxis de segmento extendida.

Probablemente esta no sea la "forma vim", pero podría ser más fácil de recordar si conoce Python.

qzr
fuente
2

Para borrar líneas impares (1,3,5, ..) -> :%s/\(.*\)\n\(.*\)\n/\2\r/g

Para borrar líneas pares (2,4,6, ..) -> :%s/\(.*\)\n.*\n/\1\r/g

Busque texto (forma la primera línea) seguido de un carácter de nueva línea y algo más de texto (forma la segunda línea) seguido de otro carácter de nueva línea y reemplace lo anterior con la primera coincidencia (línea impar) o la segunda coincidencia (línea par) seguido de retorno de carro.

kartik kailas
fuente
0

Invocar sed:

:% !sed -e '2~2 d'

^^^^                  pipe file through a shell command
    ^^^^^^            the command is sed, and -e describes an expression as parameter
            ^^^^^     starting with the second line, delete every second line
asdmin
fuente
-1

solución

puedes probar esto en vim

:1,$-1g/^/+1d

editar

Intentaré ser más claro (dos partes)

primera parte el rango de selección ( :from,to)
segunda parte la acción ( dborrar)

  • el rango si es desde la primera línea hasta la última línea ( :1,$-1)
  • globaly ( g) delete ( +1d) siguiente línea

puede intentar moverse a la primera línea de su archivo y ejecutar :+1d, verá que la siguiente línea desaparece

Sé que está embarrado, pero es vim y funciona

wdog
fuente
Claro como el barro. ¡Gracias!
Henry Henrinson