Eliminar n líneas omitir guión de 1 línea

10

Quiero crear un script Vim básico que simplemente elimine n líneas, salte 1 línea y se repita hasta el final del documento. No me interesan las coincidencias específicas, solo quiero eliminar la línea. Por ejemplo; Entonces quiero repetir el comando 3ddjpara todo el documento.

Text I want to keep.   
Text I want to delete.  
Text I want to delete.  
Text I want to delete.  
Text I want to keep.  
Text I want to delete.  
Text I want to delete.  
Text I want to delete.  
Text I want to keep.  
Text I want to delete.  
Text I want to delete.  
Text I want to delete.   

Entonces parece que ...

Text I want to keep.  
Text I want to keep.  
Text I want to keep.  

Gracias.

Max Copley
fuente
Incluyó la etiqueta regular-expressionen su pregunta, pero la pregunta no parece especificar una razón para hacerlo con expresiones regulares. Si realmente está buscando algo que use expresiones regulares, stackoverflow.com/questions/17735289/… puede ser de interés. Esa pregunta era sobre Notepad ++, pero la respuesta no usa más que una expresión regular de pcre. (Descargo de responsabilidad: escribí esa respuesta.)
Jasper
La próxima vez que haga una pregunta, no hay necesidad de escribir "Gracias por esto. ¡Gran solución!" en cada respuesta Esto incluso se escribe cuando intenta crear un nuevo comentario sobre una respuesta.
tubería
Para agregar a eso, la forma correcta de mostrar aprecio aquí es aceptar la respuesta que funcionó mejor para usted y votar las respuestas que considere útiles o útiles. La gente preferiría ver eso antes que un comentario de "gracias".
Capa B

Respuestas:

19

Enfoque muy simple:

  1. Muévase a la primera línea que desea eliminar.
  2. Grabar una macro: qa3ddjq
  3. Repítalo con un número alto: 1000 @ a

El paso tres repetirá la macro mil veces o hasta que se encuentre un error. Al presionar el final del archivo (por lo tanto, no hay líneas para eliminar) se produce un error y se cancela la repetición de la macro.

Ver :help recording.

Ralf
fuente
2
¡¡¡Eso es increíble!!! Muchas gracias, eso funcionó para mí: D
Max Copley
1
explicaciones: q(en modo comando, y en vim u otras versiones alternativas recientes [neovim, etc.], pero no en el vi original) significa "comenzar a grabar, y ponerlo en el búfer 'siguiente letra'". por lo tanto: qasignifica "comenzar a grabar en el búfer 'a'". Luego, qse registran todas las teclas escritas después de esto (hasta la siguiente en modo comando) (incluso puede grabar: entrar en modo de edición, escribir algo, escapar al modo de comando, etc.). Luego 12@arepetiría cualquier acción registrada en el búfer "a" 12 veces.
Olivier Dulac
3
Además, si no desea ejecutar algo como 1000@qal final, puede hacer una macro recursiva qa3ddj@aq@a, aunque es posible que deba hacerlo qaqprimero para asegurarse de que "acomienza vacío.
James
17

La solución más fácil para mí sería:

:%norm j3dd

Es decir:

  • %: para cada línea
  • norm: ejecuta las siguientes teclas como en modo normal
  • j3dd: bajar en línea y luego eliminar 3 líneas

Entonces, desde la primera línea, vaya a la segunda y elimine las siguientes 3 líneas. El segundo Text I want to keep.ahora está en la segunda línea. Baje una línea, elimine 3. Enjuague y repita.


Nota: si no desea procesar todo el archivo, puede reemplazarlo %normcon, por ejemplo, 5,$normpara procesar desde la quinta línea hasta el final del archivo.

Marth
fuente
44
Muy buena alternativa! Funciona en vim (no vi). ¡Nunca antes había escuchado sobre "norma"! (y soy una especie de vi [m] geek)
Olivier Dulac
6

Ya tienes algunas excelentes soluciones disponibles. Aquí hay otro:

:g/^/if line('.')%4!=1|:s/^/DELETE ME/|endif
:g/^DELETE ME/d

Primero, realizamos una acción en cada línea ( :ghaciendo coincidir el ^(inicio de línea)) y para cada número de línea realizamos el resultado de linenumber % 4. Si el resultado es desigual 1, agregamos DELETE MEal principio de la línea, marcando las líneas que se eliminarán con el siguiente comando.

El siguiente comando es un comando regular ( :g), que coincide con todas las líneas que comienzan con DELETE MEy lo hace.

Tenga en cuenta que no puede eliminar inmediatamente la línea con el primer :gcomando, ya que esto cambiaría el cálculo del módulo resultante y, como tal, primero debemos marcar las líneas y, en un segundo paso, eliminarlo.

Christian Brabandt
fuente
4

Sé que este es el vicanal, pero para mí esto es un sedproblema.

sed -ne 'p;n;n;n' <file >newfile

Para que pueda organizarlo en una visolución:

:0
!Gsed -ne 'p;n;n;n'
dgc
fuente
1
+1 para una solución sed.
Christian Brabandt
3

Una alternativa (supongo que comenzamos en la línea 1, y eliminamos las líneas 2-4, 6-8 y así sucesivamente, según un texto de ejemplo):

while line(".") < line("$")
    silent +1delete _ 3
endwhile

Si prefiere hacerlo de forma interactiva, puede utilizar el "registro de línea de comandos". Es decir, presione

:+1del 3<CR> y entonces 1000@:

Mate
fuente
1

Una alternativa: desea mantener las líneas: 1, 4, etc. Puede utilizar:

awk '!((FNR-1)%3)'  file > newfile
      # awk: when a condition is given without action:
      #        prints the lines for which the condition returns 0.
      # FNR designates the line number in the current file.
      # a%3 : takes the modulus of a and 3. ( 0%3=0, 1%3=1, 2%3=2, 3%3=0, 4%3=1, etc.) 
      # This will be 0 for 3, 6, etc. 
      # But we want it to be 0 (true) for 1, 4, etc : so we substract 1 to NR

# to see that it keeps those lines:
seq 1 20 | awk '!((NR-1)%3)'
1
4
7
10
13
16
19

Otra alternativa: si conoce las líneas que desea que coincidan con algún patrón único:

# for exemple each line you want contains "some pattern":
fgrep "some pattern" file > newfile
# (or regular grep if you want "some pattern" to be interpreted as a regexp)
Olivier Dulac
fuente