Nach Hex-Wert sortieren

14

sortWie kann ich mit coreutils numerisch nach einem Hexadezimalwert (Feld) sortieren? Ich hatte etwas in der Art von erwartet

sort -k3,3x file_to_sort

einen solchen xgibt es jedoch nicht.

Edit: Die beste Lösung, die ich bisher gefunden habe, ist:

{ echo ibase=16; cut -d' ' -f3 file_to_sort; } |
  bc | paste -d: - file_to_sort | sort -t: -k1,1n | cut -d: -f2-

Wo das cut -d' ' -f3Suchfeld isoliert (das ist -k3,3- das kann natürlich variieren) und bcin Dezimalzahlen konvertiert wird (erfordert hexadezimale Großbuchstaben ohne 0xPräfix, die mit meiner Groß- / Kleinschreibung übereinstimmen). Dann füge ich Spalten zusammen, sortiere und teile sie.

stefan
quelle
-k3,3? Sie haben Hex-Nuber, die mit 0x anstarren und alle die gleiche Länge haben? Keine Mischung aus Groß- / Kleinschreibung? Wenn ja, sollten sie richtig sortieren, wenn sie als Zeichenfolgen interpretiert werden. Vielleicht können Sie uns einige Beispieldaten zeigen?
@yeti: Leider nein.
Stefan

Antworten:

5

Eine Lösung in perl:

$ perl -anle '
    push @h, [$F[-1],$_];
    END {
        print for map  { $_->[0] }
                  sort { $a->[1] <=> $b->[1] }
                  map  { [$_->[1],hex($_->[0])] } @h;
    }
' file
4 jjk 7
5 hhf 25
2 ukr 9f
3 ezh ae
1 hdh d12

Erläuterung

  • Während der Verarbeitung der Datei erstellen wir ein Array von Array @h, wobei jedes Element eine Arrayreferenz ist [$F[-1],$_], wobei das erste Element der zu vergleichende Hex-Wert und das zweite Element die gesamte Zeile ist.

  • Im ENDBlock verwenden wir die Schwartzsche Transformation :

    • @hErstellen Sie mit jedem Element von ein anonymes Array, das die gesamte Zeile ( $_->[1]das zweite Element jedes Arrays ref in @h) und den zu vergleichenden Hexadezimalwert enthälthex($_->[0])]

    • Sortieren Sie über der Array-Basis nach dem Hex-Wert $a->[1] <=> $b->[1]

    • Holen Sie sich das erste Element jedes Arrays ref in sortiertes Array map { $_->[0] } und drucken Sie das Ergebnis.

Aktualisieren

Mit @ Joseph R's Vorschlag, ohne Schwartzian Transform zu verwenden:

$ perl -anle '
    push @h, [hex($F[-1]),$_];
    END {
        print $_->[1] for
            sort { $a->[0] <=> $b->[0] } @h;
    }
' file

Update 2

Nachdem ich den Kommentar von Stefan gelesen habe, denke ich, dass dies heißen kann direct:

$ perl -e '
    print sort {hex((split(/\s+/,$a))[-1]) <=> hex((split(/\s+/,$b))[-1])} <>;
' file
4 jjk 7
5 hhf 25
2 ukr 9f
3 ezh ae
1 hdh d12
cuonglm
quelle
+1 aber warum nicht einfach print for sort { hex $a->[-1] <=> hex $b->[-1] } @h:? Der hexBetreiber ist kaum teuer genug, um einen Schwartz zu rechtfertigen, nicht wahr?
Joseph R.
@JosephR .: Vielleicht, aber ein Schwartzianer ist flexibler und arbeitet auf jeden Fall. Ich denke, wir können eine andere Lösung haben, indem wir den Hex-Wert während der Verarbeitung berechnen. Meine Antwort wird bald aktualisiert.
Donnerstag,
Kühle Lösung. Wusste nicht, dass dieses Muster einen Namen hat: dekorieren-sortieren-undekorieren. Siehe meinen Kommentar oben.
Stefan
@ Stefan: Siehe meine aktualisierte Antwort.
Cuonglm
@ Gnouc: ja, dein 2. Update qualifiziert sich definitiv als direktes Update. meine anfängliche Vorstellung.
Stefan
6

Ich verwende diese Beispieldaten:

1 hdh d12
2 ukr 9f
3 ezh ae
4 jjk 7
5 hhf 25

Die Idee ist, eine neue Version dieser Daten mit dem Sortierfeld in Dezimalform zu erstellen. Dh awkwandelt es, prepends es jede Zeile, wird das Ergebnis sortiert und als letzten Schritt wird das hinzugefügte Feld entfernt:

awk '{val="0x" $3; sub("^0x0x","0x",val); print strtonum(val),$0 ;}' file | 
  sort -n | 
  sed 's/^[^ ]* //'

Was zu dieser Ausgabe führt:

4 jjk 7
5 hhf 25
2 ukr 9f
3 ezh ae
1 hdh d12
Hauke ​​Laging
quelle
1
Danke, ziemlich coole Lösung. Es tut mir leid, dass ich meine Bearbeitung nicht früher gepostet habe, es folgt einem ähnlichen Ansatz mit Ausschneiden + Einfügen. Ich hatte auf eine direktere Lösung gehofft ...
Stefan
@stefan Was zählt als "direkt"? Muss die Lösung verwenden sort?
Joseph R.
@ Joseph "Was zählt als" direkt "?" Ist die richtige Frage. Grundsätzlich machen alle bisherigen Lösungen (Hauke's, Gnouc's unten und meine) etwas Ähnliches: Dekodieren Sie den Hex-Wert, hängen Sie das Ergebnis an die Linien an, sortieren Sie danach und entfernen Sie es. Ich habe nach etwas gesucht, das nicht das Dekorieren-Sortieren-Undekorieren- Muster verwendet. Beide Lösungen sind meinen überlegen, da sie in einer Pipeline arbeiten. Ich habe mich für diese entschieden, weil ich persönlich lieber awk (den kleineren Hammer) als Perl für diese Art von Aufgabe verwenden würde.
Stefan
Aufgrund des zweiten Gnouc-Updates habe ich meine Antwortauswahl auf # 3 verschoben.
Stefan
1

Eingang

$ cat /tmp/input
0x45 aaa 333
0x50 dd 33
0x4 bbbb 444
0x456 cc 22
0x5 eee 1111

Sortieren eines Liners

$ gawk  --non-decimal-data '{ dec = sprintf("%d", $1); print dec " "  $0 }' /tmp/input | sort -n -k 1 | cut -f2- -d' '
0x4 bbbb 444
0x5 eee 1111
0x45 aaa 333
0x50 dd 33
0x456 cc 22

Schritt für Schritt sortieren

Schritt 1: Fügen Sie eine neue erste Spalte mit der dezimalen Darstellung der Hex-Zahl hinzu.

$ gawk  --non-decimal-data '{ dec = sprintf("%d", $1); print dec " "  $0 }' /tmp/input 
69 0x45 aaa 333
80 0x50 dd 33
4 0x4 bbbb 444
1110 0x456 cc 22
5 0x5 eee 1111

Schritt 2: Sortieren Sie die Zeilen numerisch im ersten Feld.

$ gawk  --non-decimal-data '{ dec = sprintf("%d", $1); print dec " "  $0 }' /tmp/input | sort -n -k 1
4 0x4 bbbb 444
5 0x5 eee 1111
69 0x45 aaa 333
80 0x50 dd 33
1110 0x456 cc 22

Schritt 3: Entfernen Sie die erste Spalte.

$ gawk  --non-decimal-data '{ dec = sprintf("%d", $1); print dec " "  $0 }' /tmp/input | sort -n -k 1 | cut -f2- -d' '
0x4 bbbb 444
0x5 eee 1111
0x45 aaa 333
0x50 dd 33
0x456 cc 22
Arun Saha
quelle
0

Angepasst von: http://www.unix.com/302548935-post6.html?s=b4b6b3ed50b6831717f6429113302ad6

: Zu sortierende Datei:

6F993B
954B29
A23F2F
BFA91D
C68C15
8F322F
5A6D40
6D512C
9D9D63
B4B823
A0641C
A79716
A18518

Befehl:

awk '{printf("%050s\t%s\n", toupper($0), $0)}' file-to-sort | LC_COLLATE=C sort -k1,1 | cut -f2

Ausgabe:

C68C15
BFA91D
B4B823
A79716
A23F2F
A18518
A0641C
9D9D63
954B29
8F322F
6F993B
6D512C
5A6D40

- wo der toupper ($ 0) Kleinbuchstaben "aufwertet", so dass sie zuerst sortiert werden (nicht sicher, ob das notwendig ist?)

r_alex_hall
quelle