web-dev-qa-db-fra.com

Essayer de trier sur deux champs, deuxième puis premier

J'essaie de trier sur plusieurs colonnes. Les résultats ne sont pas comme prévu.

Voici mes données (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

Les éléments suivants fonctionnent correctement:

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

Mais, ce qui suit ne fonctionne pas comme prévu:

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

J'essayais de trier par nom puis par prénom, mais vous verrez que les Villamors ne sont pas dans le bon ordre. J'espérais trier par nom de famille, puis lorsque les noms de famille correspondaient, trier par prénom.

Il semble qu'il y ait quelque chose sur la façon dont cela devrait fonctionner, je ne comprends pas. Je pourrais faire cela d'une autre manière bien sûr (en utilisant awk), mais je veux comprendre le tri.

J'utilise le shell Bash standard sur Mac OS X.

111
Harry

Une spécification clé comme -k2 signifie prendre en compte tous les champs de 2 à la fin de la ligne. Donc Villamor 44 se termine avant Villamor 50. Puisque ces deux ne sont pas égaux, la première comparaison dans sort -k2 -k1 suffit pour distinguer ces deux lignes, et la deuxième clé de tri -k1 n'est pas invoqué. Si les deux Villamors avaient eu le même âge, -k1 les aurait fait trier par prénom.

Pour trier par une seule colonne, utilisez -k2,2 comme spécification clé. Cela signifie utiliser les champs de # 2 à # 2, c'est-à-dire uniquement le deuxième champ.

sort -k2 -k3 <people.txt est redondant: c'est équivalent à sort -k2 <people.txt. Pour trier par noms de famille, puis prénoms, puis âge, exécutez la commande suivante:

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

ou équivalent sort -k2,2 -k1 <people.txt car il n'y a que ces trois champs et les séparateurs sont les mêmes. En fait, vous obtiendrez le même effet de sort -k2,2 <people.txt, car sort utilise la ligne entière en dernier recours lorsque toutes les clés d'un sous-ensemble de lignes sont identiques.

Notez également que le séparateur de champs par défaut est la transition entre un espace non vide et un espace vide, de sorte que les clés incluront les espaces de début (dans votre exemple, pour la première ligne, la première clé sera "Emily", mais la deuxième clé " Bedford". Ajouter le -b option pour supprimer ces blancs:

sort -b -k2,2 -k1,1

Cela peut également être fait sur une base par clé en ajoutant l'indicateur b à la fin de la spécification de début de clé:

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

Mais quelque chose à garder à l'esprit: dès que vous ajoutez un tel indicateur à la spécification clé, les indicateurs globaux (comme -n, -r...) ne s'appliquent plus à eux, il est donc préférable d'éviter de mélanger les indicateurs par clé et les indicateurs globaux.

Avec GNU sort vous le faites comme ça, pas sûr de MacOS:

sort -k2,2 -k1 <people.txt

Mettre à jour selon le commentaire. Cité 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.
16
manatwork