Tengo un archivo que se parece a este ejemplo de juguete. Mi archivo real tiene 4 millones de líneas, de las cuales necesito eliminar aproximadamente 10.
ID Data1 Data2
1 100 100
2 100 200
3 200 100
ID Data1 Data2
4 100 100
ID Data1 Data2
5 200 200
Quiero eliminar las líneas que se parecen al encabezado, excepto la primera línea.
Archivo final:
ID Data1 Data2
1 100 100
2 100 200
3 200 100
4 100 100
5 200 200
¿Cómo puedo hacer esto?
text-processing
Cayo Augusto
fuente
fuente
{ IFS= read -r head; printf '%s\n' "$head"; grep -vF "$head" ; } <file
head -1
ha quedado obsoleto durante décadas antes de eso.Puedes usar
Esto eliminará las líneas con ID a partir de la línea 2.
fuente
sed '2,${/^ID Data1 Data2$/d;}' file
(usando el número correcto de espacios entre las columnas, por supuesto)sed
, no.sed '1!{/ID/d;}'
Para los que no les gustan las llaves
n
significapass
línea no.1
d
eliminar todas las líneas coincidentes que comienzan con^ID
fuente
sed '1n;/^ID/d'
nombre de archivo. solo una sugerenciaIDfoo
que no son las mismas que el encabezado (es poco probable que haga una diferencia en este caso, pero nunca se sabe).Aquí hay uno divertido. Puede usar
sed
directamente para quitar todas las copias de la primera línea y dejar todo lo demás en su lugar (incluida la primera línea).1{h;n;}
coloca la primera línea en el espacio de espera, la imprime y lee en la siguiente línea, omitiendo el resto de lossed
comandos para la primera línea. (También omite esa primera1
prueba para la segunda línea , pero eso no importa ya que esa prueba no se aplicaría a la segunda línea).G
agrega una nueva línea seguida del contenido del espacio de retención al espacio del patrón./^\(.*\)\n\1$/d
elimina el contenido del espacio del patrón (saltando así a la siguiente línea) si la porción después de la nueva línea (es decir, lo que se agregó desde el espacio de retención) coincide exactamente con la porción anterior a la nueva línea. Aquí es donde se eliminarán las líneas que duplican el encabezado.s/\n.*$//
elimina la porción de texto que agregó elG
comando, de modo que lo que se imprime es solo la línea de texto del archivo.Sin embargo, dado que la expresión regular es costosa, un enfoque un poco más rápido sería usar la misma condición (negada) y
P
alinearse con la nueva línea si la porción después de la nueva línea (es decir, lo que se agregó desde el espacio de espera) no coincide exactamente con la porción antes de la nueva línea y luego elimine incondicionalmente el espacio del patrón:La salida cuando se le da su entrada es:
fuente
sed '1{h;n;};G;/^\(.*\)\n\1$/d;P;d' input
; de alguna manera es más fácil para mí leer. :)Aquí hay un par de opciones más que no requieren que conozca la primera línea de antemano:
La
-n
bandera le dice a Perl que recorra su archivo de entrada, guardando cada línea como$_
. El$k=$_ if $.==1;
guarda la primera línea ($.
es el número de línea, por$.==1
lo que solo será cierto para la primera línea) como$k
. Lasprint unless $k eq $_
impresiones de la línea actual si no es la misma que la que guarda en$k
.Alternativamente, lo mismo en
awk
:Aquí, probamos si la línea actual es la misma que la guardada en la variable
x
. Si la prueba se$0!=x
evalúa como verdadera (si la línea actual$0
no es la misma quex
), la línea se imprimirá porque la acción predeterminada para awk en expresiones verdaderas es imprimir. La primera línea (NR==1
) se guarda comox
. Dado que esto se hace después de verificar si la línea actual coincidex
, esto garantiza que la primera línea también se imprima.fuente
!($0 in a)
prueba sin crear y evita esto, o awk puede hacer la misma lógica que tiene para perl:'$0!=x; NR==1{x=$0}'
o si la línea del encabezado puede estar vacía'NR==1{x=$0;print} $0!=x'
!a[$0]
? ¿Por qué crearía eso una entradaa
?AWK es una herramienta bastante decente para tal propósito también. Aquí hay una muestra de código:
Descomponer :
NR == 1 {print}
nos dice que imprimamos la primera línea del archivo de textoNR != 1 && $0!~/ID Data1 Data2/
El operador lógico&&
le dice a AWK que imprima una línea que no es igual a 1 y que no contieneID Data1 Data2
. Tenga en cuenta la falta de{print}
parte; en awk si una condición de prueba se evalúa como verdadera, se supone que la línea se imprimirá.| head -n 10
es solo una pequeña adición para limitar la salida a solo las primeras 10 líneas. No es relevante para laAWK
parte en sí, solo se utiliza con fines de demostración.Si desea eso en un archivo, redirija la salida del comando agregando
> newFile.txt
al final del comando, así:¿Cómo se sostiene? Bastante bueno en realidad:
Nota al margen
El archivo de muestra generado se realizó con un bucle de uno a un millón e imprimió las primeras cuatro líneas de su archivo (por lo tanto, 4 líneas por millón equivalen a 4 millones de líneas), que por cierto tardó 0.09 segundos.
fuente
ID Data1 Data2 foo
que no son las mismas que el encabezado (es poco probable que haga una diferencia en este caso, pero nunca se sabe).Awk, adaptándose a cualquier encabezado automáticamente:
es decir, en la primera línea, obtenga el encabezado e imprímalo, y se imprimirá la línea posterior DIFERENTE de ese encabezado.
FNR = Número de registros en el archivo actual, para que pueda tener varios archivos y haga lo mismo en cada uno de ellos.
fuente
En aras de la exhaustividad, la solución Perl IMO es un poco más elegante que @terdon:
fuente
ID
. No tiene garantía de que esto no elimine las líneas que deben mantenerse. Desde que mencionaste la elegancia, nog
tiene sentido si lo usas^
y$
. De hecho, todas sus opcionesm///
son inútiles aquí exceptos
; activan funciones que no estás usando. Entonces, el$
,s/^ID.*//s
haría lo mismo.Solo para retroceder un poco en la pregunta ... parece que tal vez su entrada es en sí el resultado de atrapar varios archivos TSV juntos. Si puede hacer una copia de seguridad de un paso en su proceso de procesamiento (si lo posee o puede hablar con las personas que lo hacen), podría usar una herramienta de reconocimiento de encabezado para concatenar los datos en primer lugar, y así eliminar el problema de tener que eliminar líneas de encabezado adicionales.
Por ejemplo, usando Miller :
fuente