¿Cómo eliminar cada segunda línea de un archivo?


25

Archivo:

Data inserted into table. Total count 13
No error occurred
Data inserted into table. Total count 45
No error occurred
Data inserted into table. Total count 14
No error occurred
Data inserted into table. Total count 90
No error occurred

Archivo de salida esperado:

Data inserted into table. Total count 13
Data inserted into table. Total count 45
Data inserted into table. Total count 14
Data inserted into table. Total count 90

Quiero que la salida se vea de esta manera: cada segunda línea se eliminará pero no habrá espacio entre las líneas.


55
¿Desea eliminar cada segunda línea o todas las líneas que contienen "No se produjo ningún error" ? ¿Qué pasa si dos líneas consecutivas tuvieron "No se produjo ningún error" ?
Tulains Córdova

1
@ user1598390 Creo que ... en ese caso, grep -v "No error occurred" fileeste comando debería funcionar ... lo que @paul ha respondido. En el archivo de salida, no habrá líneas que contengan "No se produjo ningún error" en esta parte.
pmaipmui

1
Entonces el título de la pregunta es engañoso.
Tulains Córdova

Respuestas:


36

Con sed:

sed -e n\;d <file

Con POSIX awk:

awk 'FNR%2' <file

Si tiene más edad awk(me gusta oawk), necesita:

oawk 'NR%2 == 1' <file

Con ex:

$ ex file <<\EX
:g/$/+d
:wq!
EX

editará el archivo en el lugar.

  • g marcar un comando global
  • /$/ unir todas las líneas
  • +d eliminar la siguiente línea
  • wq! guardar todos los cambios

Este enfoque comparte el mismo ideal con el sedenfoque, elimine cada línea siguiente del inicio de línea actual de la línea 1.

Con perl:

perl -ne 'print if $. % 2' <file

y perl6:

perl6 -ne '.say if $*IN.ins % 2' <file
perl6 -ne '.say if ++$ % 2' <file

Sí ... está funcionando ... :) ... el primero está funcionando ... También he probado el segundo ... dice 'awk: error de sintaxis line1 awk: rescate cerca de la línea 1'
pmaipmui

sed -en \; d <file ~ Sí, está funcionando @cuonglm ...
pmaipmui

1
¡Supongo que usaste en n\;dlugar de 'n;d'guardar un personaje precioso, pero esa lógica desaparece cuando usas innecesariamente el -einterruptor y la redirección de un archivo <!
Tom Fenech

1
@ Geek: Es solo una versión más corta de sed -e 'n;d', te ahorra un personaje.
Cuonglm

1
@ Geek: ncomando escribir espacio de patrón en la salida estándar si -nse utilizó, luego reemplazar el espacio de patrón con la siguiente línea. Aquí se imprimirá cada línea impar n, la línea par luego se leerá en el espacio del patrón pero se eliminará inmediatamente por dcomando`.
Cuonglm

62

Resolver esto eliminando cada segunda línea puede ser propenso a errores (por ejemplo, cuando el proceso a veces genera dos líneas significativas en lugar de una). Puede ser mejor filtrar la basura:

grep -v "No error occurred" file

Puede ejecutarse como filtro, puede agregar más patrones de basura aquí y mejorar el resultado.


99
¡+1 por señalar que a veces la segunda línea es importante!
Kaz Wolfe el

12

En respuesta a la pregunta, con GNU sed:

sed '0~2d' file

eliminará cada segunda línea, pero me gustaría ofrecer líneas de filtro por contenido:

sed '/Data/! d' file

o con el mismo resultado

sed '/No error/d' file

El archivo sed '/ No error / d' ~ da el resultado deseado @Costas
pmaipmui

55
Tenga en cuenta que las dos últimas son formas complicadas de escribir grep Dataygrep -v 'No error'
Stéphane Chazelas

5

Aquí hay una manera de usar sed:

sed -n 'p;n' filename

Otra forma con GNU sed:

sed -n '1~2p' filename

Salida de los comandos anteriores:

Data inserted into table. Total count 13
Data inserted into table. Total count 45
Data inserted into table. Total count 14
Data inserted into table. Total count 90

¿A qué te refieres con decir shortest way using sed?
Cuonglm

¿Cuál es la razón al gmando? sed -n 'p;n'es suficiente.
Costas

@cuonglm: quiero decir una forma simple de hacerlo. Por cierto eliminó esa palabra. :)
serenesat

@Costas: ¡Gracias! Acabo de comprobar, está funcionando sin g. quitó g del comando. :)
serenesat

4

Puedes probar con awk:

awk 'NR % 2 != 0' file

o puede imprimir solo líneas que contengan Data inserted:

awk '$0 ~ /Data inserted/' file

He intentado las dos respuestas y ambas están funcionando ... :)
pmaipmui

3

Otra respuesta, ¡podrías usar vi / vim!

qdjddq

Y luego, si su archivo tenía 500 líneas (por ejemplo), escriba

250 @ d

Y luego escribir y salir de tipo

:X

O si algo sale mal y no quieres guardar:

: q!

Explicación:

q      #Start Recording
 d     #Put the recording into register 'd'
  j    #Move the cursor down
   dd  #Delete the line
     q #Stop recording


250    #Number of repeats
   @d  #Playback the recording in register 'd'.

2

Aquí hay una forma bastante diferente de hacerlo:

< file paste - - | cut -f1

Esto supone que las líneas impares no contienen pestañas. Si lo hacen, entonces deberá elegir otro carácter separador, por ejemplo, :aquí:

< file paste -d: - - | cut -d: -f1

1
Tenía esto en mente cuando vi la pregunta por primera vez ... Sería interesante realizar una prueba de velocidad sedcon un archivo enorme (por ejemplo, 20 mil líneas). De todos modos, +1 pero realmente, para evitar dolores de cabeza, elija un delimitador que es poco probable que ocurra en un archivo de texto, como $'\002'...
don_crissti

@don_crissti sí, el uso de un carácter no imprimible para el separador es una buena idea. Y sí, esto es mensurablemente más rápido que la solución sed. Creé un archivo de prueba con seq 100000000 > 100mil.txt. La paste|cutsolución terminó en aproximadamente 7,5 segundos, frente a casi 12 para la sedsolución. Parece ser repetible. grepSin embargo, es el más rápido. Ubuntu 14.04 con herramientas GNU estándar.
Trauma digital

Sí, paste+ cutestán muy optimizados para su trabajo, por lo que, como era de esperar, su combinación es bastante rápida ...
don_crissti


0

También resuelve el problema, aunque es un poco más lento:

vim -c "%normal jdd" -c "wq" file
Al usar nuestro sitio, usted reconoce que ha leído y comprende nuestra Política de Cookies y Política de Privacidad.
Licensed under cc by-sa 3.0 with attribution required.