2009-03-13 19 views
6

Para usar el comando uniq, primero debe ordenar su archivo.¿Cómo mantener el formato de un archivo si usa el comando uniq (en shell)?

Pero en el archivo que tengo, el orden de la información es importante, por lo tanto, ¿cómo puedo conservar el formato original del archivo pero aún así deshacerme del contenido duplicado?

+0

¿Quieres mantener sólo la primera aparición del patrón? ¿O solo el último? Tienes que ser un poco más específico que esto ... – wzzrd

+0

Bueno, el archivo es algo como esto. pattern1 patrón2 Pattern3 pattern4 pattern1 patrón2 etc ... pattern1 difiere de patrón2, y así sucesivamente. P. ej.) Patrón1 es un título, y patrón2 es un número de teléfono. Si ordeno el archivo, los números de teléfono no estarán bajo el título correcto, etc. – Dennis

+0

Olvidé que esta sección de comentarios no conserva el formato. Entonces, la publicación anterior puede ser un poco difícil de entender. – Dennis

Respuesta

10

Otra versión awk:

awk '!_[$0]++' infile 
+0

O (n) solución en 8 bytes. +1 – ashawley

+0

¡jaja, lindo! ¿como funciona? (+1) –

+0

ah, ahora veo :) –

0

Usted podría tomar alguna (n^2) O algo horrible, como este (pseudo-código):

file2 = EMPTY_FILE 
for each line in file1: 
    if not line in file2: 
    file2.append(line) 

Esto es potencialmente bastante lento, especialmente si se aplica a nivel Bash. Pero si sus archivos son razonablemente cortos, probablemente funcionen bien y se implementen rápidamente (not line in file2 es entonces grep -v, y así sucesivamente).

De lo contrario, podría codificar un programa dedicado, usando una estructura de datos más avanzada en la memoria para acelerarlo.

+0

Gracias relajarse. El archivo que tengo ahora es solo un archivo de muestra, por lo que es bastante corto. Pero los archivos en los que lo usaré serán grandes. Veré lo que otros sugieren, y probablemente voy a probar tu sugerencia por ahora. – Dennis

1

Puede ejecutar -d uniq de la versión clasificada del archivo para encontrar las líneas duplicadas, a continuación, ejecutar una secuencia de comandos que dice:

if this_line is in duplicate_lines { 
    if not i_have_seen[this_line] { 
     output this_line 
     i_have_seen[this_line] = true 
    } 
} else { 
    output this_line 
} 
+0

El beneficio de hacer esto en lugar de soluciones ligeramente más simples, por cierto, es que no se mantiene un mapeo de cada línea en el archivo, solo las líneas duplicadas. – chaos

+0

oh espera. no pensó en -d. tonto litb. así la comunicación se puede cortar a continuación :) –

+0

edición final después de poner en -d en lugar de usar comm: ordenar archivo.txt | uniq -d | awk 'FNR == NR {dups [$ 0]; } FNR! = NR {if ($ 0 en dups) {if (! ($ 0 en líneas)) {print $ 0; líneas [$ 0]; }} else imprimir $ 0; } '- file.txt –

4

Este awk mantiene la primera aparición. Mismo algoritmo que otras respuestas utilizar:

awk '!($0 in lines) { print $0; lines[$0]; }' 

Aquí hay uno que sólo necesita almacenar líneas duplicadas (a diferencia de todas las líneas) utilizando awk:

sort file | uniq -d | awk ' 
    FNR == NR { dups[$0] } 
    FNR != NR && (!($0 in dups) || !lines[$0]++) 
' - file 
0
for line in $(sort file1 | uniq); do 
    grep -n -m1 line file >>out 
done; 

sort -n out 

primero haga el tipo,

para cada grep de valor único para la primera coincidencia (-m1)

y conservar los números de línea

ordenar la salida numéricamente (-n) por número de línea.

entonces podría quitar la línea # 's con sed o awk

4

También está el método de "número de línea, de doble tipo".

nl -n ln | sort -u -k 2| sort -k 1n | cut -f 2- 
+0

+1 para una solución que funciona con archivos muy grandes. Pero ¿no debería ser "ordenar -k 1n" (tipo numérico)? –

+0

sí, tienes razón. – ashawley

1

Usando sólo uniq y grep:

Crear d.sh:

#!/bin/sh 
sort $1 | uniq > $1_uniq 
for line in $(cat $1); do 
cat $1_uniq | grep -m1 $line >> $1_out 
cat $1_uniq | grep -v $line > $1_uniq2 
mv $1_uniq2 $1_uniq 
done; 
rm $1_uniq 

Ejemplo:

./d.sh infile 
Cuestiones relacionadas