¿Cómo obtener solo los resultados únicos sin tener que ordenar los datos?

40
$ cat data.txt 
aaaaaa
aaaaaa
cccccc
aaaaaa
aaaaaa
bbbbbb
$ cat data.txt | uniq
aaaaaa
cccccc
aaaaaa
bbbbbb
$ cat data.txt | sort | uniq
aaaaaa
bbbbbb
cccccc
$

El resultado que necesito es mostrar todas las líneas del archivo original eliminando todos los duplicados (no solo los consecutivos), manteniendo el orden original de las declaraciones en el archivo .

Aquí, en este ejemplo, el resultado que realmente estaba buscando era

aaaaaa
cccccc
bbbbbb

¿Cómo puedo realizar esta uniqoperación generalizada en general?

Lazer
fuente

Respuestas:

54
perl -ne 'print unless $seen{$_}++' data.txt

O, si debe tener un uso inútil decat :

cat data.txt | perl -ne 'print unless $seen{$_}++'

Aquí hay una awktraducción, para sistemas que carecen de Perl:

awk '!seen[$0]++' data.txt
cat data.txt | awk '!seen[$0]++'
cjm
fuente
3
Un script awk un poco más corto es{ if (!seen[$0]++) print }
camh
1
@fred, a menos que su archivo sea realmente enorme, cualquiera de las versiones tarda más en escribir que ejecutar.
cjm
8
La versión de awk se puede hacer aún más corto, dejando fuera las if, print, paréntesis y corchetes:awk '!seen[$0]++'
Gordon Davisson
2
@Legate, es el nombre de una matriz en la que estamos grabando cada línea que hemos visto. Puede cambiarlo '!LarryWall[$0]++'para todas las preocupaciones de awk, pero "visto" ayuda a las personas a comprender mejor el programa.
cjm
1
@Sadi, eso realmente debería haberse hecho como una pregunta, no como un comentario. Pero algunas de las líneas en ese archivo terminan en un espacio, y otras no. Estos comandos consideran que toda la línea es significativa, incluido el espacio en blanco al final.
cjm
13

John tiene una herramienta llamada unique:

usr@srv % cat data.txt | unique out
usr@srv % cat out
aaaaaa
cccccc
bbbbbb

Lograr lo mismo sin herramientas adicionales en una sola línea de comandos es un poco más complejo:

usr@srv % cat data.txt | nl | sort -k 2 | uniq -f 1 | sort -n | sed 's/\s*[0-9]\+\s\+//'
aaaaaa
cccccc
bbbbbb

nlimprime números de línea delante de las líneas, por lo que si nosotros sort/ uniqdetrás de ellas, podemos restaurar el orden original de las líneas. sedsimplemente elimina los números de línea después;)

binfalse
fuente
¿Hay alguna combinación de comandos de Linux comunes que puedan hacer lo mismo?
Lazer
77
¿Qué te perdiste en "sin tener que ordenar los datos"?
Totor
@Totor: vea la respuesta de menkus a un comentario similar. @binfalse: su segunda solución no funciona (tal vez funciona con esta muestra trivial pero no funciona con algunos datos de la vida real). nl -ba -nrz data.txt | sort -k2 -u | sort | cut -f2
Arregle
6

Prefiero usar esto:

cat -n data.txt | sort --key=2.1 -b -u | sort -n | cut -c8-

cat -n agrega números de línea,

sort --key=2.1 -b -u se ordena en el segundo campo (después de los números de línea agregados), ignorando los espacios en blanco iniciales, manteniendo líneas únicas

sort -n se ordena en estricto orden numérico

cut -c8- mantenga todos los caracteres de la columna 8 a EOL (es decir, omita los números de línea que incluimos)

menkus
fuente
55
> ¿Cómo obtener solo los resultados únicos sin tener que ordenar los datos? > sin tener que ordenar datos
Jan Wikholm
77
'sin tener que ordenar los datos' solo aparece en el título. La necesidad real es: "mostrar todas las líneas del archivo original eliminando todos los duplicados (no solo los consecutivos), mientras se mantiene el orden original de las declaraciones en el archivo".
menkus
1
@menkus la clave es "mientras se mantiene el orden original de las declaraciones en el archivo". Esta respuesta no logra eso.
Andrew Ferrier
2

Perl tiene un módulo que puede usar que incluye una función llamada uniq. Entonces, si tiene sus datos cargados en una matriz en Perl, simplemente llame a la función de esta manera para que sea única, pero aún así mantenga el orden original.

use List::MoreUtils qw(uniq)    
@output = uniq(@output);

Puede leer más sobre este módulo aquí: Lista :: MoreUtils

slm
fuente
¿Puede esto manejar archivos grandes, por ejemplo, 500 GB?
Niño