¿Cuál es la diferencia entre "sort -u" y "sort | uniq "?

120

En todas partes veo a alguien que necesita obtener una lista ordenada y única, a la que siempre se dirigen sort | uniq. Nunca he visto ningún ejemplo en el que alguien use en su sort -ulugar. Por qué no? ¿Cuál es la diferencia, y por qué es mejor usar uniq que la bandera única para ordenar?

Benubird
fuente

Respuestas:

120

sort | uniqexistía antes sort -uy es compatible con una gama más amplia de sistemas, aunque casi todos los sistemas modernos son compatibles -u: es POSIX. Es principalmente un retroceso a los días en sort -uque no existía (y las personas no tienden a cambiar sus métodos si la forma en que saben continúa funcionando, solo miren ifconfigvs. ipadopción).

Los dos probablemente se fusionaron porque eliminar duplicados dentro de un archivo requiere ordenación (al menos, en el caso estándar), y es un caso de uso extremadamente común. También es más rápido internamente como resultado de poder realizar ambas operaciones al mismo tiempo (y debido al hecho de que no requiere IPC entre uniqy sort). Especialmente si el archivo es grande, sort -uprobablemente usará menos archivos intermedios para ordenar los datos.

En mi sistema constantemente obtengo resultados como este:

$ dd if=/dev/urandom of=/dev/shm/file bs=1M count=100
100+0 records in
100+0 records out
104857600 bytes (105 MB) copied, 8.95208 s, 11.7 MB/s
$ time sort -u /dev/shm/file >/dev/null

real        0m0.500s
user        0m0.767s
sys         0m0.167s
$ time sort /dev/shm/file | uniq >/dev/null

real        0m0.772s
user        0m1.137s
sys         0m0.273s

Tampoco oculta el código de retorno de sort, que puede ser importante (en los shells modernos hay formas de obtener esto, por ejemplo, bashla $PIPESTATUSmatriz, pero esto no siempre fue cierto).

Chris Down
fuente
31
Tiendo a usarlo sort | uniqporque 9 de cada 10 veces, de hecho, estoy conectado uniq -c.
Plutor
55
Tenga en cuenta que sort -uera parte de la 7ª Edición de UNIX, alrededor de 1979. Las versiones sortsin soporte -uson verdaderamente arcaicas, o se escribieron sin prestar atención al estándar de facto antes del estándar de jure de POSIX. Ver también Stack Overflow Sort & uniq en Linux Shell desde 2010.
Jonathan Leffler
3
+1 por ip. Es 2016 y esta publicación en 2013, pero solo sé sobre el ipcomando ahora.
final
44
+1 para "9 veces fuera 10 en realidad estoy canalizando uniq -c" (y tal vez canalizando una vez más sort -nr | head). Me preguntaba a qué equivale sort | uniqen Vim cuando descubrí que Vim tiene el :sort umando. Y TIL sort -uexiste también.
Zhuoyun Wei
Tenga en cuenta que hay una diferencia cuando se usa sort -n | uniqcontra sort -n -u. Por ejemplo, los espacios en blanco iniciales y finales serán vistos como duplicados sort -n -upor el primero, pero no por el primero. echo -e 'test \n test' | sort -n -uvuelve test, pero echo -e 'test \n test' | sort -n | uniqdevuelve ambas líneas.
mxmlnkn
46

Una diferencia es que uniqtiene una serie de opciones adicionales útiles, como omitir campos para comparar y contar el número de repeticiones de un valor. sortLa -ubandera solo implementa la funcionalidad del uniqcomando sin adornos .

CLF
fuente
3
+0.49 para obtener una respuesta útil, pero lo diría algo así como " sort -uNo se puede pasar la salida de uniqpara usar algunas de las opciones útiles de esta última, como omitir campos para comparar y contar el número de repeticiones".
l0b0
15
+1 para compensar a los detractores porque "no hay forma de hacer esto directamente desde el tipo" responde la pregunta ...
Izkata
42

Con sorts y uniqs compatibles con POSIX (GNU uniqactualmente no es compatible en ese sentido), hay una diferencia en que sortusa el algoritmo de clasificación de la configuración regional para comparar cadenas (generalmente se usará strcoll()para comparar cadenas) mientras se uniqverifica la identidad del valor de byte (generalmente se usará strcmp()) .

Eso es importante por al menos dos razones.

  • En algunos entornos locales, especialmente en los sistemas GNU, hay diferentes caracteres que ordenan lo mismo. Por ejemplo, en la configuración regional en_US.UTF-8 en un sistema GNU, todos los caracteres ①②③④⑤⑥⑦⑧⑨⑩ ... y muchos otros se ordenan de la misma manera porque su orden de clasificación no está definido. Los dígitos árabes 0123456789 se clasifican de la misma manera que sus contrapartes índicas árabes orientales (٠١٢٣٤٥٦٧٨٩).

    Para sort -u, ① ordena lo mismo que ② y 0123 lo mismo que ٠١٢٣, por sort -ulo que retendría solo uno de cada uno, mientras que para uniq(no GNU uniqque usa strcoll()(excepto con -i)), ① es diferente de ② y 0123 es diferente de ٠١٢٣, por uniqlo que consideraría todos 4 únicos.

  • strcollsolo puede comparar cadenas de caracteres válidos (el comportamiento no está definido según POSIX cuando la entrada tiene secuencias de bytes que no forman caracteres válidos), mientras que strcmp()no le importan los caracteres, ya que solo hace una comparación byte a byte. Entonces, esa es otra razón por la cual es sort -uposible que no le proporcione todas las líneas únicas si algunas de ellas no forman un texto válido. sort|uniq, aunque todavía no se ha especificado en la entrada sin texto, en la práctica es más probable que le proporcione líneas únicas por ese motivo.

Además de esas sutilezas, una cosa que no se ha notado hasta ahora es que uniqcompara la línea completa léxicamente, mientras que sortla -ucomparación se basa en la especificación de clasificación dada en la línea de comando.

$ printf '%s\n' 'a b' 'a c' | sort -uk 1,1
a b
$ printf '%s\n' 'a b' 'a c' | sort -k 1,1 | uniq
a b
a c

$ printf '%s\n' 0 -0 +0 00 '' | sort -n | uniq
0
-0
+0
00

$ printf '%s\n' 0 -0 +0 00 '' | sort -nu
0
Stéphane Chazelas
fuente
9

Prefiero usarlo sort | uniqporque cuando trato de usar la -uopción (eliminar duplicados) para eliminar duplicados que involucran cadenas de mayúsculas y minúsculas, no es tan fácil entender el resultado.

Nota: antes de poder ejecutar los ejemplos a continuación, debe simular la secuencia de clasificación C estándar haciendo lo siguiente:

LC_ALL=C
export LC_ALL

Por ejemplo, si quiero ordenar un archivo y eliminar duplicados, al mismo tiempo, mantengo distintos casos de cadenas.

$ cat short      #file to sort
Pear
Pear
apple
pear
Apple

$ sort short     #normal sort (in normal C collating sequence)
Apple            #the lower case words are at the end
Pear
Pear
apple
pear

$ sort -f short  #correctly sorts ignoring the C collating order
Apple            #but duplicates are still there
apple
Pear
Pear
pear

$ sort -fu short #By adding the -u option to remove duplicates it is 
apple            #difficult to ascertain the logic that sort uses to remove
Pear             #duplicates(i.e., why did it remove pear instead of Pear?)

Esta confusión se resuelve al no usar la -uopción para eliminar duplicados. Usar uniqes más predecible. Lo siguiente primero ordena e ignora el caso y luego lo pasa uniqpara eliminar los duplicados.

$ sort -f short | uniq
Apple
apple
Pear
pear
Jerry Marbas
fuente
2
-uopción de sortsalidas el primero de una ejecución igual (ver página de manual) Por lo tanto, sort -furecoge la primera aparición de cada línea única que no distingue entre mayúsculas y minúsculas. La lógica que se sortusa para eliminar duplicados es predecible.
pallxk
3

Otra diferencia que descubrí hoy es al ordenar en base a un delimitador donde se sort -uaplica la bandera única solo en la columna con la que se ordena.

$ cat input.csv
3,World,1
1,Hello,1
2,Hello,1

$ cat input.csv | sort -t',' -k2 -u
1,Hello,1
3,World,1

$ cat input.csv | sort -t',' -k2 | uniq
1,Hello,1
2,Hello,1
3,World,1
Stefanos Chrs
fuente
Esto se menciona en una respuesta de Stéphane Chazelas, pero me gusta tu ejemplo, así que +1
roaima
Gracias por señalar @roaima, no estaba muy claro en esa respuesta
Stefanos Chrs