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

120

Em todo lugar que vejo alguém precisando obter uma lista exclusiva e classificada, eles sempre acessam sort | uniq. Eu nunca vi nenhum exemplo em que alguém use sort -u. Por que não? Qual é a diferença e por que é melhor usar o uniq do que o sinalizador exclusivo para classificar?

Benubird
fonte

Respostas:

120

sort | uniqexistia antes sort -ue é compatível com uma ampla gama de sistemas, embora quase todos os sistemas modernos sejam compatíveis -u- é o POSIX. É principalmente um retrocesso para os dias em sort -uque não existia (e as pessoas não tendem a mudar seus métodos se a maneira que eles sabem continuar a funcionar, basta olhar ifconfigcontra a ipadoção).

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

No meu sistema, eu sempre obtenho 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

Ele também não mascarar o código de retorno sort, que pode ser importante (em conchas modernas existem maneiras de conseguir isso, por exemplo, bashda $PIPESTATUSmatriz, mas isso nem sempre era verdade).

Chris Down
fonte
31
Eu costumo usar sort | uniqporque, em 9 vezes em 10, estou realmente procurando uniq -c.
Plutor
5
Observe que sort -ufazia parte da 7ª Edição UNIX, por volta de 1979. As versões sortsem suporte para -usão verdadeiramente arcaicas - ou foram escritas sem atenção ao padrão de fato antes do padrão de jure do POSIX. Veja também Stack Overflow Sort & uniq no shell Linux a partir de 2010.
Jonathan Leffler
3
+1 por causa de ip. É 2016 e este post em 2013, mas agora só sei sobre ipcomando.
dieend 27/05
4
+1 em "9 vezes 10" Estou na verdade canalizando para uniq -c"(e talvez canalizando mais uma vez sort -nr | head)". Fiquei me perguntando o que é equivalente sort | uniqno Vim quando descobri que o Vim tem :sort ucomando. E o TIL também sort -uexiste.
Zhuoyun Wei 13/10
Note-se que há uma diferença quando se utiliza sort -n | uniqvs. sort -n -u. Por exemplo, espaços em branco à direita e à esquerda serão vistos como duplicados pelo sort -n -umas não pelo anterior! echo -e 'test \n test' | sort -n -uretorna test, mas echo -e 'test \n test' | sort -n | uniqretorna as duas linhas.
Mxmlnkn
46

Uma diferença é que uniqexistem várias opções adicionais úteis, como ignorar campos para comparação e contar o número de repetições de um valor. sortO -usinalizador de apenas implementa a funcionalidade do uniqcomando sem adornos .

CLF
fonte
3
+0,49 para uma resposta útil, mas eu a chamaria de algo como " sort -uNão é possível transmitir a saída de uniqpara usar algumas das opções úteis desta última, como pular campos para comparação e contar o número de repetições".
L0b0
15
+1 para compensar os pessimistas porque "não há nenhuma maneira de fazer isso diretamente do tipo" faz responder à pergunta ...
Izkata
42

Com sorts e s compatíveis com POSIX uniq( uniqatualmente, o GNU não é compatível com isso), há uma diferença no sortuso do algoritmo de intercalação do código do idioma para comparar seqüências de caracteres (normalmente será usado strcoll()para comparar sequências) enquanto uniqverifica a identidade de valor de byte (normalmente será usado strcmp()) .

Isso importa por pelo menos duas razões.

  • Em algumas localidades, especialmente nos sistemas GNU, existem caracteres diferentes que são iguais. Por exemplo, no código de idioma en_US.UTF-8 em um sistema GNU, todos os caracteres ①②③④⑤⑥⑦⑧⑨⑩ ... e muitos outros classificam da mesma forma porque sua ordem de classificação não está definida. Os dígitos arábicos 0123456789 têm a mesma classificação de seus equivalentes árabes orientais (٠١٢٣٤٥٦٧٨٩).

    Para sort -u, orts é igual a ② e 0123 o mesmo que ٠١٢٣, portanto sort -u, retém apenas um de cada um, enquanto que para uniq(não o GNU uniqque usa strcoll()(exceto com -i)), ① é diferente de ② e 0123 diferente de ٠١٢٣, portanto uniqconsideraria tudo 4 únicos.

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

Além dessas sutilezas, uma coisa que não foi notada até agora é que uniqcompara a linha inteira lexicamente, enquanto sorta -ucompara 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
Stéphane Chazelas
fonte
9

Prefiro usar sort | uniqporque, quando tento usar a opção -u(eliminar duplicatas) para remover duplicatas que envolvem seqüências de maiúsculas e minúsculas, não é tão fácil entender o resultado.

Nota: para poder 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, mantendo ao mesmo tempo os diferentes casos de strings.

$ 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?)

Essa confusão é resolvida não usando a -uopção para remover duplicatas. O uso uniqé mais previsível. O primeiro abaixo classifica e ignora o caso e depois o passa uniqpara remover as duplicatas.

$ sort -f short | uniq
Apple
apple
Pear
pear
Jerry Marbas
fonte
2
-uopção de gerar sorta primeira de uma corrida igual (consulte a página de manual). Assim, sort -fucapta a primeira ocorrência de cada linha exclusiva que não diferencia maiúsculas de minúsculas. A lógica sortusada para remover duplicatas é previsível.
pallxk
3

Outra diferença que descobri hoje é ao classificar com base em um delimitador onde sort -uaplica o sinalizador exclusivo apenas na coluna que 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
Stefanos Chrs
fonte
Isso é mencionado em uma resposta de Stéphane Chazelas mas eu gosto do seu exemplo para +1
roaima
Obrigado por apontar @roaima, não foi muito claro em que a resposta
Stefanos Chrs