Trier les lignes non triées avec un tuyau '|' en elle correctement

17

J'essaie de trier quelques données simples délimitées par des tuyaux. Cependant, le tri n'est pas réellement un tri. Il déplace ma ligne d'en-tête vers le bas, mais mes deux lignes commençant par 241 sont divisées par une ligne commençant par 24.

cat sort_fail.csv
column_a|column_b|column_c
241|212|20810378
24|121|2810172
241|213|20810376

sort sort_fail.csv
241|212|20810378
24|121|2810172
241|213|20810376
column_a|column_b|column_c

Les en-têtes de colonne sont déplacés vers le bas du fichier, donc le tri est clairement en train de le traiter. Mais, les valeurs réelles ne sont pas triées comme je m'y attendais.

Dans ce cas, j'ai travaillé avec

sort sort_fail.csv --field-separator='|' -k1,1

Mais je pense que cela ne devrait pas être nécessaire. Pourquoi le tri n'est-il pas le tri?

user10777668
la source
2
utiliser LC_COLLATE=C sort. Selon ce à quoi vous vous attendez, vous devrez peut-être aussiLC_COLLATE=C sort -t'|' -n
mosvy
3
Pour trier les données de "style csv" à csvsortpartir csvkitdesquelles vous pouvez utiliser , qui gèrent correctement les valeurs entre guillemets.
Bakuriu

Réponses:

32

sort est sensible aux paramètres régionaux, donc en fonction de votre paramètre LC_COLLATE (hérité de LANG), vous pouvez obtenir des résultats différents:

$ LANG=C sort sort_fail.csv 
241|212|20810378
241|213|20810376
24|121|2810172
column_a|column_b|column_c

$ LANG=en_US sort sort_fail.csv
241|212|20810378
24|121|2810172
241|213|20810376
column_a|column_b|column_c

Cela peut provoquer des problèmes dans les scripts, car vous ne savez peut-être pas à quoi les paramètres régionaux d'appel sont définis et vous pouvez donc obtenir des résultats différents.

Il n'est pas rare que les scripts forcent le réglage nécessaire

par exemple

$ grep 'LC.*sort' /bin/precat
      LC_COLLATE=C sort -u | prezip-bin -z "$cmd: $2"

Maintenant, ce qui est intéressant, ici, c'est que le |personnage a l'air bizarre.

Mais c'est parce que la règle par défaut pour en_US, qui dérive de l'ISO, dit

$ grep 007C /usr/share/i18n/locales/iso14651_t1_common
<U007C> IGNORE;IGNORE;IGNORE;<j> # 142 |

Ce qui signifie que le |caractère est ignoré et l'ordre de tri serait comme si le caractère n'existait pas.

$ tr -d '|' < sort_fail.csv | LANG=C sort
24121220810378
241212810172
24121320810376
column_acolumn_bcolumn_c

Et cela correspond au tri "inattendu" que vous voyez.

Les solutions sont d'utiliser -n(pour forcer les tris numériques), ou d'utiliser le séparateur de champs (comme vous l'avez fait) ou d'utiliser les Cparamètres régionaux.

Stephen Harris
la source
Fascinant. J'ai vu d'autres succès sur la localisation, mais j'ai pensé que cela aurait un impact sur l'ordre relatif de 24 contre 241, pas quelque chose comme ça.
user10777668
7
quelque chose de très utile dans le tri GNU est l' --debugoption, qui indique la clé (soulignée) utilisée pour comparer
Jeff Schaller
courir avec --debug souligne juste toute la ligne - sort inclut le caractère pipe, il est juste configuré pour n'avoir aucun impact à cause de la localisation. C'est une bonne fonctionnalité mais ne m'a pas aidé dans ce cas (j'ai essayé :)
user10777668
C'est exactement pourquoi je l'ai mentionné, @ user10777668 - cela indique que sortla ligne entière est utilisée au lieu de s'arrêter aux caractères que nous supposons.
Jeff Schaller
Je ne m'attendais pas à ce que ça s'arrête. Je m'attendais à ce qu'il reconnaisse le caractère de la pipe et l'inclue dans le tri, traitant donc 24 | 1 et 241 différemment. Je ne sais pas comment --debug aurait changé cela, et en fait étant donné qu'il souligne le | semble que cela aurait activement détourné l'attention du vrai problème où la localisation a conduit à ce que le caractère de pipe soit ingéré
user10777668
1

Ce qui m'irrite, c'est que le 24ne bouge pas de sa place entre les deux 241. Le deuxième champ commence par un 1. En essayant le tri avec un leader 4dans le deuxième champ, le 24est déplacé vers le bas, donc je soupçonne sortsimplement d'ignorer le |sauf indication contraire. Essayez sort -n...

RudiC
la source
1

-n, --numeric-sort comparer en fonction de la valeur numérique de la chaîne

210
23

Sans le -n, 210 par texte est en avance sur 23 car il va caractère mon caractère.

michaelkrieger
la source
Vous avez raison, mais cela n'explique pas que le caractère du tuyau soit différent. Les autres réponses montrent qu'en raison des paramètres régionaux, le canal est traité comme n'étant pas là, donc le chiffre suivant est ce qui décide de l'ordre.
Criggie