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
- aplawrence.com/Unixart/sort-vs-uniq.html
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 parauniq -c
. - Observe que
sort -u
fazia parte da 7ª Edição UNIX, por volta de 1979. Versões desort
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 comandoip
agora. - +1 para ” 9 vezes 10 I ‘ m realmente canalizando para
uniq -c
” (e talvez canalizando mais uma vez parasort -nr | head
). Eu estava me perguntando o que é equivalente asort | uniq
no Vim quando descobri que o Vim tem o comando:sort u
. E TILsort -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 porsort -n -u
, mas não pelo primeiro!echo -e 'test \n test' | sort -n -u
retornatest
, masecho -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 parauniq
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 ٠١٢٣, portantosort -u
reteria apenas um de cada, enquanto parauniq
(não GNUuniq
que usastrcoll()
(exceto com-i
)), ① é diferente de ② e 0123 diferente de ٠١٢٣, entãouniq
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) enquantostrcmp()
não se importa sobre caracteres, uma vez que só faz comparação byte a byte. Portanto, esse é outro motivo pelo qualsort -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 desort
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 quesort
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