Tri de plusieurs clés avec le tri Unix

137

J'ai des fichiers potentiellement volumineux qui doivent être triés par clés 1-n. Certaines de ces touches peuvent être numériques et d'autres non. Il s'agit d'un fichier en colonnes de largeur fixe, il n'y a donc pas de délimiteurs.

Y a-t-il un bon moyen de faire cela avec le tri Unix? Avec une touche, c'est aussi simple que d'utiliser «-n». J'ai lu la page de manuel et cherché brièvement sur Google, mais je n'ai pas trouvé un bon exemple. Comment pourrais-je y parvenir?

Remarque: j'ai exclu Perl en raison de la taille potentielle du fichier. Ce serait un dernier recours.

Chris Kloberdanz
la source
Une ou deux lignes d'exemple de données seraient vraiment utiles pour créer un exemple de ligne de commande. De plus, les clés «1-n» signifient-elles que vous devez trier par un nombre variable de clés? Faire ça sans script va être amusant ...
Ken Gentle
J'ai un wrapper PHP autour de la commande sort pour activer la fonctionnalité 1-n.
Chris Kloberdanz

Réponses:

69

Utilisez l' -koption (ou --key=POS1[,POS2]). Il peut apparaître plusieurs fois et chaque clé peut avoir des options globales (comme npour le tri numérique)

Ken Gentle
la source
7
Depuis la page de manuel de tri: "POS est F [.C] [OPTS], où F est le numéro de champ et C la position du caractère dans le champ; les deux sont l'origine 1." Voir la page de manuel pour une documentation complète.
Adam Rosenfield
49
Voir aussi la réponse d'Andras si vous ne voulez pas devenir fou.
ron
1
Les deux commentaires ci-dessus sont précis et additifs. Merci, messieurs.
Ken Gentle
314

Attention cependant:

Si vous souhaitez trier le fichier principalement par le champ 3, et secondairement par le champ 2, vous voulez ceci:

sort -k 3,3 -k 2,2 < inputfile

Not this: sort -k 3 -k 2 < inputfile qui trie le fichier par la chaîne du début du champ 3 à la fin de la ligne (qui est potentiellement unique).

-k, --key=POS1[,POS2]     start a key at POS1 (origin 1), end it at POS2
                          (default end of line)
Andras
la source
8
Changement de vie. Merci.
davidtbernal
2
Oups! Maintenant, je dois corriger un script parce que plus tôt je n'ai vu que la première réponse ci-dessus ... bonne chose que je n'ai pas encore dépendu de la sortie du script ....
Wildcard
Agréable! Maintenant, que se passe-t-il si je veux que le fleld 3 soit trié numériquement et inversé alors que le champ 2 doit être trié non numériquement et normal (croissant)? :)
Arun
2
@Arun POS est expliqué à la fin de la page de manuel. Vous ajoutez simplement les options de commande au numéro de champ comme ceci:sort -k 3,3nr -k 2,2
andras
1
Aargh. Quelle interface contre-intuitive: -k2devrait être -k2,2et une virgule de fin -k2,devrait être «fin de ligne par défaut magique ou autre».
android.weasel
94

L'option -k est ce que vous voulez.

-k 1.4,1.5n -k 1.14,1.15n

Utiliserait les positions de caractère 4-5 dans le premier champ (c'est tout un champ pour une largeur fixe) et trierait numériquement comme première clé.

La deuxième clé serait également les caractères 14-15 dans le premier champ.

(Éditer)

Exemple (tout ce que j'ai, c'est DOS / cygwin à portée de main):

dir | \cygwin\bin\sort.exe -k 1.4,1.5n -k 1.40,1.60r

pour les données:

12/10/2008  01:10 PM         1,564,990 outfile.txt

Trie la liste du répertoire par numéro de mois (pos 4-5) numériquement, puis par nom de fichier (pos 40-60) à l'envers. Puisqu'il n'y a pas d'onglets, c'est tout le champ 1 à trier.

Clinton Pierce
la source
Ce n'est qu'un champ s'il n'y a pas de blancs dans les données d'entrée. Néanmoins, votre exemple est utile.
Jonathan Leffler
Correction: s'il n'y a pas de / tabs / dans les données d'entrée. Dans la sortie de la commande 'dir' de DOS, il n'y a pas d'onglets.
Clinton Pierce
Les exemples sur la façon d'utiliser les options (numérique, inverse) sont extrêmement utiles, car il est presque impossible de savoir comment utiliser uniquement à partir de la page de manuel et les autres réponses ne l'ont pas mentionné. J'aimerais pouvoir +2 pour cela. ;)
msb
22

En voici une pour trier les différentes colonnes d'un fichier csv par ordre numérique et dictionnaire, colonnes 5 et suivantes comme ordre dictionnaire

~/test>sort -t, -k1,1n -k2,2n -k3,3d -k4,4n -k5d  sort.csv
1,10,b,22,Ga
2,2,b,20,F
2,2,b,22,Ga
2,2,c,19,Ga
2,2,c,19,Gb,hi
2,2,c,19,Gb,hj
2,3,a,9,C

~/test>cat sort.csv
2,3,a,9,C
2,2,b,20,F
2,2,c,19,Gb,hj
2,2,c,19,Gb,hi
2,2,c,19,Ga
2,2,b,22,Ga
1,10,b,22,Ga

Notez que -k1,1n signifie numérique commençant à la colonne 1 et se terminant à la colonne 1. Si je l'avais fait ci-dessous, il aurait concaténé les colonnes 1 et 2, ce qui ferait 1,10 trié comme 110

~/test>sort -t, -k1,2n -k3,3 -k4,4n -k5d  sort.csv
2,2,b,20,F
2,2,b,22,Ga
2,2,c,19,Ga
2,2,c,19,Gb,hi
2,2,c,19,Gb,hj
2,3,a,9,C
1,10,b,22,Ga
edW
la source
1
C'est la meilleure réponse car elle montre comment utiliser différents commutateurs pour différentes colonnes
xaxa
12

Je crois dans ton cas quelque chose comme

sort -t@ -k1.1,1.4 -k1.5,1.7 ... <inputfile

fonctionnera mieux. @ est le séparateur de champ, assurez-vous qu'il s'agit d'un caractère qui n'apparaît nulle part. alors votre entrée est considérée comme constituée d'une colonne.

Edit: apparemment, clintp a déjà donné une réponse similaire, désolé. Comme il le fait remarquer, les drapeaux «n» et «r» peuvent être ajoutés à chaque option -k ....

Dong Hoon
la source
Même si le séparateur par défaut selon docs gnu.org/software/coreutils/manual/html_node/... est l'espace, parfois le nombre de champs n'est pas ce à quoi vous vous attendez. Peut-être comme d'autres l'ont dit ici à cause du paramètre de locale LC_CTYPE. En cas de doute, comptez depuis le début de la ligne!
Brad Dre
5

Notez qu'il peut également être souhaitable de stabiliser le tri avec le -scommutateur, de sorte que les lignes de rang égal conservent également leur ordre relatif d'origine dans la sortie.

Ron
la source
2

Je veux juste ajouter quelques conseils, lorsque vous utilisez le tri, faites attention à vos paramètres régionaux qui affectent l'ordre de la comparaison clé. J'utilise généralement explicitement LC_ALL = C pour faire de la locale ce que je veux.

jianpx
la source
LC_ALL = C peut également entraîner une accélération considérable!
mat kelcey