Was ist der Unterschied zwischen den Optionen --general-numeric-sort und --numeric-sort in gnu sort?

113

sortbietet zwei Arten der numerischen Sortierung. Dies ist von der Manpage:

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

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

Was ist der Unterschied?

Trenton
quelle
17
Beachten Sie, dass die vollständige Dokumentation von sortnicht die manSeite, sondern die infoSeite ( info sort) ist.
A3M

Antworten:

85

Die allgemeine numerische Sortierung vergleicht die Zahlen als Gleitkommazahlen. Dies ermöglicht eine wissenschaftliche Notation, z. B. 1.234E10, ist jedoch langsamer und unterliegt einem Rundungsfehler (1.2345678 könnte nach 1.2345679 kommen). Die numerische Sortierung ist nur eine reguläre alphabetische Sortierung, bei der 10 nach 9 steht.

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

'-g' '--general-numeric-sort' '--sort = general-numeric' Mit der Standard-C-Funktion strtod numerisch sortieren, um ein Präfix jeder Zeile in eine Gleitkommazahl mit doppelter Genauigkeit umzuwandeln. Dies ermöglicht die Angabe von Gleitkommazahlen in wissenschaftlicher Notation wie 1.0e-34 und 10e100. Das Gebietsschema LC_NUMERIC bestimmt das Dezimalzeichen. Melden Sie keine Überlauf-, Unterlauf- oder Konvertierungsfehler. Verwenden Sie die folgende Sortierfolge: Zeilen, die nicht mit Zahlen beginnen (alle werden als gleich angesehen). NaNs ("Not a Number" -Werte in IEEE-Gleitkomma-Arithmetik) in einer konsistenten, aber maschinenabhängigen Reihenfolge. Minus unendlich. Endliche Zahlen in aufsteigender numerischer Reihenfolge (mit -0 und +0 gleich). Plus unendlich.

Verwenden Sie diese Option nur, wenn es keine Alternative gibt. Es ist viel langsamer als --numeric-sort (-n) und kann beim Konvertieren in Gleitkommazahlen Informationen verlieren.

'-n' '--numeric-sort' '--sort = numeric' Numerisch sortieren. Die Zahl beginnt in jeder Zeile und besteht aus optionalen Leerzeichen, einem optionalen '-' - Zeichen und null oder mehr Ziffern, die möglicherweise durch Tausende Trennzeichen getrennt sind, optional gefolgt von einem Dezimalzeichen und null oder mehr Ziffern. Eine leere Zahl wird als '0' behandelt. Das Gebietsschema LC_NUMERIC gibt das Dezimalzeichen und das Tausendertrennzeichen an. Standardmäßig ist ein Leerzeichen ein Leerzeichen oder eine Registerkarte, das Gebietsschema LC_CTYPE kann dies jedoch ändern.

Der Vergleich ist genau; Es liegt kein Rundungsfehler vor.

Weder ein führendes '+' noch eine exponentielle Notation werden erkannt. Verwenden Sie die Option --general-numeric-sort (-g), um solche Zeichenfolgen numerisch zu vergleichen.

Martin Beckett
quelle
2
Vielen Dank. Seltsam, dass die Mann- und Infoseiten dies nicht enthalten. Ich wusste auch nichts über gnu.org/software/coreutils/manual/html_node/index.html .
Trenton
6
Dieses Zeug funktioniert nicht für mich. Ich sortiere eine Datei mit einer dritten Spalte mit Inhalten wie R1 R2 R10 R15. Mit entweder -k3.2noder -k3.2gwird R10vorher sortiert R2. Die Sortierung ist lexikografisch und nicht numerisch. Ich erwarte, dass das Feld ab dem zweiten Zeichen als Zahl behandelt wird.
Kaz
6
@Kaz: sort's Schlüsselspezifikationen. sind wirklich byzantinisch - das kurze daran ist: Die Leerzeichen vor dem Feld werden als Teil des Feldes betrachtet , also char. Index 1 zeigt auf das (erste) Leerzeichen vor dem Feld, nicht auf das tatsächliche erste Zeichen des Feldes. Suffix das Zeichen. Index mit b, um dieses Problem zu beheben, dh: -k 3.2bn,3(Beachten Sie, dass die globale -b Option in diesem Fall nicht funktioniert). Beachten Sie auch das hinzugefügte ,3, das sicherstellt, dass nur das 3. Feld verwendet wird - ohne diesen 2. Feldindex wird der Rest der gesamten Zeile verwendet.
mklement0
11

Sie sollten mit Ihrem Gebietsschema vorsichtig sein. Beispielsweise möchten Sie möglicherweise eine gleitende Zahl (wie 2.2) sortieren, während Ihr Gebietsschema möglicherweise die Verwendung eines Kommas (wie 2,2) erwartet.

Wie in diesem Forum berichtet , können Sie mit den Flags -n oder -g falsche Ergebnisse erzielen.

In meinem Fall benutze ich:

LC_ALL=C sort -k 6,6n file

um die 6. Spalte zu sortieren, die enthält:

2.5
3.7
1.4

um zu erhalten

1.4
2.5
3.7
JFL
quelle
2
Selbst mit LANG = C kann ich -nKomma nicht als Tausendertrennzeichen erkennen - "1.000" wird genauso behandelt wie "1".
Scott
1
Das sollte LC_ALL = C sein.
Stuart P. Bentley
@Scott: In der Tat werden Tausende Trennzeichen NICHT erkannt: sortVerwendet die Logik mit dem längsten Präfix : Der längste Teil der Zeile / des Schlüssels, den er als Zahl erkennt, wird verwendet. In einem Gebietsschema, das .als Radix-Zeichen verwendet wird, hört das Lesen bei auf ,.
mklement0
@ StuartP.Bentley: LC_ALL=Cist in der Tat die robusteste Wahl; Wenn jedoch LC_ALLnicht gesetzt LANG=Cwird, funktioniert dies auch.
mklement0
1
Guter Punkt, ist aber LANG=C sort -k 6,6n filesowohl einfacher als auch lokalisiert den Effekt des Festlegens von Umgebungsvariablen LANGauf den spezifischen Befehl.
mklement0
0

Zusätzlich zu der akzeptierten Antwort, die -geine wissenschaftliche Notation zulässt , möchte ich den Teil zeigen, der höchstwahrscheinlich unerwünschtes Verhalten verursacht.

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

Schauen Sie sich die zoodrei wichtigen Dinge hier an:

  • Die Linie beginnt mit NAN(zB Nanaund nani lol) oder -INF(einzelner Bindestrich, nicht--INF ) bis zum Ende, jedoch vor den Ziffern. Während INFUmzug in den letzten nach Ziffern , weil es bedeutet, unendlich .

  • Die NAN,INF und -INFsind Groß- und Kleinschreibung .

  • Die Zeilen ignorieren Leerzeichen immer von beiden Seiten NAN, INF, -INF (unabhängig davon LC_CTYPE). Andere alphabetische Zeichen können Leerzeichen von beiden Seiten ignorieren, abhängig vom GebietsschemaLC_COLLATELC_COLLATE=fr_FR.UTF-8 ignorieren (z. B. ignorieren, aber LC_COLLATE=us_EN.UTF-8nicht ignorieren).

Wenn Sie also beliebige alphanumerische Zeichen sortieren, möchten Sie dies wahrscheinlich nicht-g . Wenn Sie wirklich einen Vergleich der wissenschaftlichen Notation mit benötigen -g, möchten Sie wahrscheinlich alphabetische und numerische Daten extrahieren und den Vergleich separat durchführen .

Wenn Sie nur eine normale Nummer benötigen (z 1, -1 ) und dies für 0x/E/+ sortingnicht wichtig halten, verwenden Sie einfach -ngenug:

$ 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

Entweder -goder -n, sich bewusst sein locale Wirkung . Sie können angeben möchten LC_NUMERICalsus_EN.UTF-8 zu vermeiden fr_FR.UTF-8 Art -mit schwimmender Nummer fehlgeschlagen :

$ 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

Mit 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

Oder LC_NUMERIC=us_EN.UTF-8zu gruppieren+|-|space mit 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

Sie möchten wahrscheinlich localebei der Verwendung angeben , sortob ein tragbares Skript geschrieben werden soll.

Obst
quelle