Qual é a diferença entre “ sort -u ” e “ sort | uniq ”?

Sempre que vejo alguém precisando obter uma lista única e classificada, eles sempre direcionam para sort | uniq. Nunca vi nenhum exemplo em que alguém use sort -u em vez disso. Por que não? Qual é a diferença, e por que é melhor usar uniq do que o sinalizador exclusivo para classificar?

Comentários

Resposta

sort | uniq existia antes de sort -u, e é compatível com uma gama mais ampla de sistemas, embora quase todos os sistemas modernos suportem -u – é POSIX. É principalmente um retrocesso aos dias em que sort -u não existia (e as pessoas não tendem a mudar seus métodos se a maneira que conhecem continua a funcionar, basta olhar para ifconfig vs. ip adoção).

Os dois provavelmente foram mesclados porque a remoção de duplicatas em um arquivo requer classificação (pelo menos, no padrão caso), e é um caso de uso extremamente comum. Também é mais rápido internamente como resultado de poder fazer as duas operações ao mesmo tempo (e devido ao fato de que não requer IPC entre uniq e sort). Especialmente se o arquivo for grande, sort -u provavelmente usará menos arquivos intermediários para classificar os dados.

No meu sistema Eu obtenho consistentemente 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 

Também não mascara o código de retorno de sort, que pode ser importante (em shells modernos, existem maneiras de obter isso, por exemplo, bash “s $PIPESTATUS array, mas isso não era sempre verdadeiro).

Comentários

  • Eu costumo usar sort | uniq porque 9 em cada 10 vezes, Eu ‘ estou realmente canalizando para uniq -c.
  • Observe que sort -u fazia parte da 7ª Edição UNIX, por volta de 1979. Versões de sort sem t suporte para -u são verdadeiramente arcaicos – ou foram escritos sem atenção ao padrão de facto antes do POSIX ‘ padrão de jure. Veja também Stack Overflow Classifique & uniq no shell do Linux de 2010.
  • +1 porque de ip. É ‘ 2016 e esta postagem em 2013, mas eu só sei sobre o comando ip agora.
  • +1 para ” 9 vezes 10 I ‘ m realmente canalizando para uniq -c ” (e talvez canalizando mais uma vez para sort -nr | head). Eu estava me perguntando o que é equivalente a sort | uniq no Vim quando descobri que o Vim tem o comando :sort u. E TIL sort -u também existe.
  • Observe que há uma diferença ao usar sort -n | uniq vs. sort -n -u. Por exemplo, espaços em branco à direita e à esquerda serão vistos como duplicatas por sort -n -u, mas não pelo primeiro! echo -e 'test \n test' | sort -n -u retorna test, mas echo -e 'test \n test' | sort -n | uniq retorna ambas as linhas.

Resposta

Uma diferença é que uniq tem uma série de opções adicionais úteis, como pular campos para comparação e contar o número de repetições de um valor. O sinalizador sort “s -u implementa apenas a funcionalidade do comando uniq sem adornos.

Comentários

  • +0,49 para uma resposta útil, mas eu colocaria algo como ” A saída de sort -u pode ‘ t ser passado para uniq para usar parte do último ‘ s opções úteis, como pular campos para comparação e contar o número de repetições. ”
  • +1 para compensar o oponentes porque ” não ‘ não há como fazer isso diretamente do tipo ” responde à pergunta …

Resposta

Com sort se uniq s (GNU uniq atualmente não é compatível a esse respeito), há “uma diferença em que sort usa o algoritmo de agrupamento do local para comparar strings (normalmente usará strcoll() para comparar strings) enquanto uniq verifica a identidade do valor de byte (normalmente usa strcmp()) ¹.

Isso é importante por pelo menos dois motivos .

  • Em alguns locais, especialmente em sistemas GNU, existem diferentes caracteres que são classificados da mesma forma. Por exemplo, no local en_US.UTF-8 em um sistema GNU, todos os ①②③④⑤⑥⑦⑧⑨⑩ … caracteres² e muitos outros são classificados da mesma forma porque sua ordem de classificação não está definida. Os dígitos 0123456789 árabes são classificados da mesma forma que seus correspondentes Índico árabe oriental (٠١٢٣٤٥٦٧٨٩).

    Para sort -u, ① classifica o mesmo que ② e 0123 o mesmo que ٠١٢٣, portanto sort -u reteria apenas um de cada, enquanto para uniq (não GNU uniq que usa strcoll() (exceto com -i)), ① é diferente de ② e 0123 diferente de ٠١٢٣, então uniq consideraria todos os 4 únicos.

  • strcoll só pode comparar strings de caracteres válidos (o comportamento é indefinido de acordo com POSIX quando a entrada tem sequências de bytes que não formam caracteres válidos) enquanto strcmp() não se importa sobre caracteres, uma vez que só faz comparação byte a byte. Portanto, esse é outro motivo pelo qual sort -u pode não fornecer a você todas as linhas exclusivas se algumas delas não formarem um texto válido. sort|uniq, embora não seja especificado na entrada não textual, na prática é mais provável que forneça linhas exclusivas por esse motivo.

Além dessas sutilezas, uma coisa que não foi observada até agora é que uniq compara toda a linha lexicamente, enquanto sort “s -u compara com base na especificação de classificação fornecida na linha 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 

¹ Versões anteriores da especificação POSIX estavam causando confusão, no entanto, ao listar a variável LC_COLLATE como uma que afetava uniq, que foi removida na edição 2018 e o comportamento foi esclarecido após a discussão mencionada acima. Veja o bug do grupo Austin correspondente

² 2019 edite . Esses já foram corrigidos, mas mais de 95% dos pontos de código Unicode ainda têm uma ordem indefinida a partir da versão 2.30 do GNU libc . Você pode testar com 🧙🧚🧛🧜🧝 em vez de, por exemplo, em versões mais novas

Resposta

Eu prefiro usar sort | uniq porque quando tento usar a opção -u (eliminar duplicatas) para remover duplicatas envolvendo sequências de maiúsculas e minúsculas, não é tão fácil entenda o resultado.

Observação: antes de executar os exemplos abaixo, você precisa simular a sequência de intercalação C padrão fazendo o seguinte:

LC_ALL=C export LC_ALL 

Por exemplo, se eu quiser classificar um arquivo e remover duplicatas, enquanto, ao mesmo tempo, mantenho os diferentes casos de strings distintos.

$ 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 confusão é resolvida ao não usar a opção -u para remover duplicatas. Usar uniq é mais previsível. O seguinte primeiro classifica e ignora o caso e, em seguida, o passa para uniq para remover as duplicatas.

$ sort -f short | uniq Apple apple Pear pear 

Comentários

  • -u opção de sort gera o primeiro de uma execução igual (consulte a página do manual). Assim, sort -fu pega a primeira ocorrência de cada linha única sem distinção entre maiúsculas e minúsculas. A lógica que sort usa para remover duplicatas é previsível.

Resposta

Outra diferença que descobri hoje é ao classificar com base em um delimitador, onde sort -u aplica o sinalizador exclusivo apenas na coluna com a qual você classifica.

$ 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 

Comentários

  • Isso é mencionado em uma resposta de St é phane Chazelas, mas Gosto do seu exemplo, então +1
  • Obrigado por apontar @roaima, não foi ‘ t muito claro nessa resposta

Deixe uma resposta

O seu endereço de email não será publicado. Campos obrigatórios marcados com *