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.
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.