Quelle est la différence entre les options --general-numeric-sort et --numeric-sort dans GNU Sort

113

sortfournit deux types de tri numérique. Ceci provient de la page de manuel:

   -g, --general-numeric-sort
          compare according to general numerical value

   -n, --numeric-sort
          compare according to string numerical value

Quelle est la différence?

Trenton
la source
17
Notez que la documentation complète de sortn'est pas la manpage mais la infopage ( info sort).
a3nm

Réponses:

85

Le tri numérique général compare les nombres sous forme de flottants, cela permet la notation scientifique, par exemple 1.234E10, mais est plus lent et sujet à une erreur d'arrondi (1.2345678 pourrait venir après 1.2345679), le tri numérique est juste un tri alphabétique régulier qui sait que 10 vient après 9.

Voir http://www.gnu.org/software/coreutils/manual/html_node/sort-invocation.html

'-g' '--general-numeric-sort' '--sort = general-numeric' Trier numériquement, en utilisant la fonction standard C strtod pour convertir un préfixe de chaque ligne en un nombre à virgule flottante double précision. Cela permet de spécifier les nombres à virgule flottante en notation scientifique, comme 1.0e-34 et 10e100. Les paramètres régionaux LC_NUMERIC déterminent le caractère décimal. Ne signalez pas les erreurs de dépassement de capacité, de dépassement inférieur ou de conversion. Utilisez la séquence de classement suivante: Lignes qui ne commencent pas par des nombres (toutes considérées comme égales). NaNs (valeurs «Not a Number», en arithmétique à virgule flottante IEEE) dans un ordre cohérent mais dépendant de la machine. Moins l'infini. Nombres finis dans l'ordre numérique croissant (avec -0 et +0 égaux). Plus l'infini.

Utilisez cette option uniquement s'il n'y a pas d'alternative; il est beaucoup plus lent que --numeric-sort (-n) et il peut perdre des informations lors de la conversion en virgule flottante.

'-n' '--numeric-sort' '--sort = numeric' Trier numériquement. Le nombre commence chaque ligne et se compose de blancs facultatifs, d'un signe facultatif «-» et de zéro ou plusieurs chiffres éventuellement séparés par des milliers de séparateurs, éventuellement suivis d'un caractère décimal et de zéro ou plus de chiffres. Un nombre vide est traité comme «0». Les paramètres régionaux LC_NUMERIC spécifient le caractère décimal et le séparateur des milliers. Par défaut, un espace est un espace ou une tabulation, mais les paramètres régionaux LC_CTYPE peuvent changer cela.

La comparaison est exacte; il n'y a pas d'erreur d'arrondi.

Ni un '+' ni une notation exponentielle n'est reconnu. Pour comparer ces chaînes numériquement, utilisez l'option --general-numeric-sort (-g).

Martin Beckett
la source
2
Merci. Il est étrange que les pages man et info n'en contiennent pas. Je ne connaissais pas non plus gnu.org/software/coreutils/manual/html_node/index.html .
Trenton
6
Ce truc ne fonctionne pas pour moi. Je trie un fichier avec une troisième colonne avec un contenu comme R1 R2 R10 R15. En utilisant soit -k3.2nou -k3.2g, c'est un tri R10avant R2. Le tri est lexicographique et non numérique. Je m'attends à ce qu'il traite le champ à partir du deuxième caractère comme un nombre.
Kaz
6
Spécifications sortclés de @Kaz: sont vraiment byzantins - en bref: le ou les blancs précédant le champ sont considérés comme faisant partie du champ , donc char. l'index 1 pointe vers le (premier) blanc précédant le champ, pas le premier caractère réel du champ. Suffixez le caractère. index avec bpour résoudre ce problème, c'est-à-dire: -k 3.2bn,3(notez que l' option globale -b ne fonctionne pas dans ce cas). Notez également l'ajout ,3, qui garantit que seul le troisième champ est utilisé - sans ce deuxième index de champ, le reste de la ligne entière est utilisé.
mklement0
11

Vous devez faire attention à vos paramètres régionaux. Par exemple, vous pourriez avoir l'intention de trier un nombre flottant (comme 2.2) alors que vos paramètres régionaux peuvent s'attendre à l'utilisation d'une virgule (comme 2,2).

Comme indiqué dans ce forum , vous pouvez avoir des résultats erronés en utilisant les indicateurs -n ou -g.

Dans mon cas, j'utilise:

LC_ALL=C sort -k 6,6n file

afin de trier la 6ème colonne qui contient:

2.5
3.7
1.4

afin d'obtenir

1.4
2.5
3.7
JFL
la source
2
Même avec LANG = C, je n'arrive pas -nà reconnaître la virgule comme séparateur de milliers - «1 000» est traité de la même façon que «1».
Scott
1
Cela devrait être LC_ALL = C.
Stuart P. Bentley
@Scott: En effet, les séparateurs de milliers ne sont PAS reconnus: sortutilise la logique du préfixe le plus long: la partie la plus longue de la ligne / clé qu'il reconnaît comme un nombre est utilisée; dans un environnement local qui utilise .comme caractère de base, la lecture s'arrêtera à ,.
mklement0
@ StuartP.Bentley: LC_ALL=Cest en effet le choix le plus robuste ; cependant, si vous LC_ALLne pariez pas, LANG=Ccela fonctionnera aussi.
mklement0
1
Bon point, mais LANG=C sort -k 6,6n fileest à la fois plus simple et localise également l'effet de la définition de la variable d'environnement LANGsur la commande spécifique.
mklement0
0

En plus de la réponse acceptée qui mentionne -gautoriser la notation scientifique , je veux montrer la partie qui cause le plus vraisemblablement un comportement indésirable.

Avec -g:

$ LC_COLLATE=fr_FR.UTF-8 LC_NUMERIC=en_US.UTF-8 sort -g myfile
baa
--inf
--inf  
--inf- 
--inf--
--inf-a
--nnf
nnf--
   nnn  
tnan
zoo
   naN
Nana
nani lol
-inf
-inf--
-11
-2
-1
1
+1
2
+2
0xa
11
+11
inf

Regardez les zootrois choses importantes ici:

  • La ligne commence par NAN(par exemple Nanaet nani lol) ou -INF(un seul tiret, pas --INF) se déplace vers la fin mais avant les chiffres. Tandis que INFpasser au dernier après les chiffres car cela signifie l'infini .

  • Les NAN, INFet -INFsont insensibles à la casse .

  • Les lignes ignorent toujours des espaces de part et d' autre NAN, INF, -INF (quel que soit LC_CTYPE). D'autres alphabétiques peuvent ignorer les espaces de chaque côté en fonction de la localisation LC_COLLATE(par exemple LC_COLLATE=fr_FR.UTF-8ignorer mais LC_COLLATE=us_EN.UTF-8pas ignorer).

Donc, si vous triez des caractères alphanumériques arbitraires, vous ne voulez probablement pas -g. Si vous avez vraiment besoin d'une comparaison de notation scientifique avec -g, vous voudrez probablement extraire des données alphabétiques et numériques et faire une comparaison séparément .

Si vous n'avez besoin que d'un 1, -1tri de nombres ordinaires (par exemple ) et que vous pensez que cela 0x/E/+ sortingn'est pas important, utilisez juste -nassez:

$ LC_COLLATE=fr_FR.UTF-8 LC_NUMERIC=en_US.UTF-8 sort -n myfile
-1000
-22
-13
-11
-010
-10
-5
-2
-1
-0.2
-0.12
-0.11
-0.1
0x1
0x11
0xb
+1
+11
+2
-a
-aa
--aa
-aaa
-b
baa
BAA
bbb
+ignore
inf
-inf
--inf
--inf  
--inf- 
--inf--
-inf--
--inf-a
   naN
Nana
nani lol
--nnf
nnf--
   nnn  
None         
uum
Zero cool
-zzz
1
1.1
1.234E10
5
11

Soit -gou -n, soyez conscient de l' effet des paramètres régionaux . Vous voudrez peut-être spécifier LC_NUMERICque us_EN.UTF-8 pour éviter le tri fr_FR.UTF-8 -avec un nombre flottant a échoué :

$ LC_COLLATE=fr_FR.UTF-8 LC_NUMERIC=fr_FR.UTF-8 sort -n myfile
-10
-5
-2
-1
-1.1
-1.2
-0.1
-0.11
-0.12
-0.2
-a
+b
middle
-wwe
+zoo
1
1.1

Avec LC_NUMERIC=en_US.UTF-8:

$ LC_COLLATE=fr_FR.UTF-8 LC_NUMERIC=en_US.UTF-8 sort -n myfile
-10
-5
-2
-1.2
-1.1
-1
-0.2
-0.12
-0.11
-0.1
-a
+b
middle
-wwe
+zoo
1
1.1

Ou LC_NUMERIC=us_EN.UTF-8pour grouper +|-|spaceavec alpha:

$ LC_COLLATE=fr_FR.UTF-8 LC_NUMERIC=us_EN.UTF-8 sort -n myfile
-0.1
    a
    b
 a
 b
+b
+zoo
-a
-wwe
middle
1

Vous voudrez probablement spécifier localelors de l'utilisation sortsi vous voulez écrire un script portable.

Fruit
la source