Tentando classificar em dois campos, segundo e primeiro

90

Estou tentando classificar várias colunas. Os resultados não são os esperados.

Aqui estão meus dados (people.txt):

Simon Strange 62
Pete Brown 37
Mark Brown 46
Stefan Heinz 52
Tony Bedford 50
John Strange 51
Fred Bloggs 22
James Bedford 21
Emily Bedford 18
Ana Villamor 44
Alice Villamor 50
Francis Chepstow 56

Os seguintes itens funcionam corretamente:

bash-3.2$ sort -k2 -k3 <people.txt                                                                                                                    
Emily Bedford 18                                                                                                                                      
James Bedford 21                                                                                                                                      
Tony Bedford 50                                                                                                                                       
Fred Bloggs 22                                                                                                                                        
Pete Brown 37                                                                                                                                         
Mark Brown 46                                                                                                                                         
Francis Chepstow 56                                                                                                                                   
Stefan Heinz 52                                                                                                                                       
John Strange 51                                                                                                                                       
Simon Strange 62                                                                                                                                      
Ana Villamor 44                                                                                                                                       
Alice Villamor 50

Mas o seguinte não funciona como esperado:

bash-3.2$ sort -k2 -k1 <people.txt                                        
Emily Bedford 18                                                                                                                                      
James Bedford 21                                                                                                                                      
Tony Bedford 50                                                                                                                                       
Fred Bloggs 22                                                                                                                                        
Pete Brown 37                                                                                                                                         
Mark Brown 46                                                                                                                                         
Francis Chepstow 56                                                                                                                                   
Stefan Heinz 52                                                                                                                                       
John Strange 51                                                                                                                                       
Simon Strange 62                                                                                                                                      
Ana Villamor 44                                                                                                                                       
Alice Villamor 50

Eu estava tentando classificar por sobrenome e depois pelo primeiro nome, mas você verá que os Villamors não estão na ordem correta. Eu esperava classificar por sobrenome e, em seguida, quando os sobrenomes combinavam, para classificar pelo primeiro nome.

Parece que há algo sobre como isso deve funcionar, eu não entendo. Eu poderia fazer isso de outra maneira (usando o awk), mas eu quero entender o tipo.

Estou usando o shell Bash padrão no Mac OS X.

    
por Harry 24.10.2012 / 14:12

2 respostas

130

Uma especificação de chave como -k2 significa considerar todos os campos de 2 até o final da linha. Então, Villamor 44 acaba antes de Villamor 50 . Como esses dois não são iguais, a primeira comparação em sort -k2 -k1 é suficiente para discriminar essas duas linhas, e a segunda chave de classificação -k1 não é invocada. Se os dois Villamors tivessem a mesma idade, -k1 teria feito com que eles fossem classificados pelo primeiro nome.

Para classificar por uma única coluna, use -k2,2 como especificação de chave. Isso significa usar os campos de 2 a 2, ou seja, apenas o segundo campo.

sort -k2 -k3 <people.txt é redundante: é equivalente a sort -k2 <people.txt . Para classificar por sobrenomes, depois os primeiros nomes e, em seguida, idade, execute o seguinte comando:

sort -k2,2 -k1,1 <people.txt

ou equivalentemente sort -k2,2 -k1 <people.txt , pois existem apenas esses três campos e os separadores são os mesmos. De fato, você obterá o mesmo efeito de sort -k2,2 <people.txt , porque sort usa a linha inteira como último recurso quando todas as chaves em um subconjunto de linhas são idênticas.

Observe também que o separador de campo padrão é a transição entre um não-branco e um vazio, então as chaves incluirão os espaços em branco à esquerda (no seu exemplo, para a primeira linha, a primeira será "Emily" , mas a segunda chave " Bedford" . Adicione a opção -b para remover esses espaços em branco:

sort -b -k2,2 -k1,1

Também pode ser feito em uma base por chave, adicionando o sinal b no final da especificação de início de chave:

sort -k2b,2 -k1,1 <people.txt

Mas é importante ter em mente: assim que você adicionar um sinalizador à especificação de chave, os sinalizadores globais (como -n , -r ...) não serão mais aplicados a eles, por isso é melhor evitar misturar sinalizadores por chave e sinalizadores globais.

    
por 24.10.2012 / 23:25
16

Com o GNU sort você faz assim, não tenho certeza sobre o MacOS:

sort -k2,2 -k1 <people.txt

Atualizar de acordo com o comentário. Citado de man sort :

   -k, --key=KEYDEF
          sort via a key; KEYDEF gives location and type

   KEYDEF is F[.C][OPTS][,F[.C][OPTS]] for start and stop position, where
   F is a field number and C a character position in the field; both are
   origin 1, and the stop position defaults to the line's end.
    
por 24.10.2012 / 14:15

Tags