Classifique o arquivo CSV por prioridade de coluna usando o comando “sort”

91

Tenho um arquivo csv e gostaria de classificá-lo por prioridade de coluna, como "ordenar por". Por exemplo:

3;1;2
1;3;2
1;2;3
2;3;1
2;1;3
3;2;1

Se esta situação fosse o resultado de uma "seleção", o "ordenar por" seria o seguinte: ordenar por coluna2, coluna1, coluna3 - o resultado seria:

2;1;3
3;1;2
1;2;3
3;2;1
1;3;2
2;3;1

Eu gostaria de saber como obter este mesmo resultado usando o comando "sort" no Unix.

Rafael Orágio
fonte
4
A propósito, esse é um arquivo ssv (valores separados por ponto e vírgula): P
John Strood

Respostas:

153
sort --field-separator=';' --key=2,1,3
Charlie Martin
fonte
8
Se os valores forem numéricos, então provavelmente você desejará usar a -nopção que irá "comparar de acordo com o valor numérico da string" ou a -gopção que irá "comparar de acordo com o valor numérico geral". Uma comparação de string de valores numéricos obterá os números ordenados da mesma forma 1,10,2,20. Pelo menos essas são opções disponíveis na minha versão do tipo no CentOS. Você deve verificar na página do manual quais são as opções corretas em sua versão de classificação.
Adam Porad
4
Eu recebosort: stray character in field spec: invalid field specification ‘2,1,3’
Martin Thoma
3
No entanto, sort --field-separator=',' -r -k3 -k1 -k2 source.csv > target.csvfuncionou para mim.
Martin Thoma
6
@MartinThoma já faz muito tempo, mas encontrei seu problema e descobri sort --field-separator=';' --key={2,1,3}. Funcionou GNU coreutils 8.4desde abril de 2016
Mrbolichi
2
@mrbolichi a notação --key={2,1,3}usa expansão de chave de bash
kvantour
28

Suponha que você tenha outra linha 3;10;3em seu unsorted.csvarquivo. Então eu acho que você espera um resultado classificado numericamente:

2;1;3
3;1;2
1;2;3
3;2;1
1;3;2
2;3;1
3;10;3

e não em ordem alfabética:

2;1;3
3;1;2
3;10;3
1;2;3
3;2;1
1;3;2
2;3;1

Para conseguir isso, você deve usar -n:

sort --field-separator=';' -n -k 2,2 -k 1,1 -k 3,3 unsorted.csv

Vale ressaltar que 2,2tem que ser usado. Se 2for usado, sortleva a string do início do campo 2 ao final. 2,2garante que apenas o campo 2seja usado.

Martin Thoma
fonte
7
O indicador quanto à diferença entre -k 2 e -k 2,2 é significativo! Eu tinha esquecido isso na minha primeira leitura da página do manual. Obrigado.
usonianhorizon
Eu adicionei algumas linhas extras, 3;10;3, 3:10:5, 3:10;2, 3;10;3nessa ordem no arquivo de origem, e quando se utiliza apenas -k 2,2 parece classificar coluna 2 e 3. A página homem diz "The -k option may be specified multiple times, in which case subsequent keys are compared when earlier keys compare equal.". No meu caso, a chave anterior (valor = 10) comparou igual, no entanto, não especifiquei -kvárias vezes. Não tenho certeza se esse é um comportamento confiável ou relacionado ao meu sistema (mac). Em última análise, não importa, contanto que a classificação primária seja correta.
Davos
Ah, vejo que também existe -sum tipo estável que ignora as chaves iguais, que aparentemente é mais rápido de acordo com o homem.
Davos
24

A resposta de Charlie acima não funcionou para mim no Cygwin (classificar versão 2.0, GNU textutils), o seguinte funcionou:

sort -t"," -k2 -k1 -k1
Samuel Kerrien
fonte
3
Cygwin tem uma versão mais antiga do tipo. Como sempre, a página do manual é sua.
Charlie Martin de
2
Eu concordo com @CharlieMartin, você deve verificar a página de manual em seu sistema. No CentOS eu useisort --field-separator=';' -k2 -k1 -k3 test.csv
Adam Porad
-6

..e se alguém seguiu a solução de 'classificação', mas agora deseja obter mais do que uma única entrada única por linha (ou seja, o número X principal de entradas exclusivas), uma vez que você classificou o arquivo usando 'classificar', você pode usar um pequeno aplicativo que criei aqui:

https://github.com/danieliversen/MiscStuff/blob/master/scripts/findTopUniques.java

Daniel Iversen
fonte
2
Bom para você! Mas, no seu caso, você poderia apenas usar cat unsorted-file | sort | uniq | head -X- quando Xé o número de primeiras linhas que deseja imprimir.
Slavik Meltser
@SlavikMe Muito obrigado pelo comentário! No entanto, sua sugestão fornece um resultado diferente. Sua sugestão obtém as primeiras X linhas no arquivo totalmente classificado, enquanto queríamos obter as primeiras X linhas por "chave" (ou seja, se você tiver um CSV com nomes, então se você classificar pela coluna 2, "sobrenome", então seus comandos talvez tenham apenas 3 linhas com "Allen" como o sobrenome, enquanto os nossos receberiam "Allen", "Brittain", "Charles" etc.). Obrigado!
Daniel Iversen
6
você está errado. Eu teria sugerido experimentar o comando que escrevi antes de comentar. Observe que há um comando uniqna ordem dos tubos, entre o sorte o head, que confere exclusividade a todas as linhas classificadas imediatamente antes da extração das linhas superiores.
Slavik Meltser