ordina per valore esadecimale


14

Utilizzando coreutils sort, come posso ordinare numericamente per valore esadecimale (campo)? Mi aspettavo qualcosa del genere

sort -k3,3x file_to_sort

tuttavia, tale xnon esiste.

Modifica: la migliore soluzione che ho trovato finora è:

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

dove cut -d' ' -f3isola il campo di ricerca (questo è -k3,3- questo può variare, ovviamente) e bcfa la conversione in decimale (richiede esadecimale maiuscolo, senza 0xprefisso, corrispondente al mio caso). Quindi unisco, ordina e divido le colonne.


-k3,3? Hai nubers esadecimali che fissano con 0x e tutti della stessa lunghezza? Nessun mix di maiuscolo / minuscolo? Se sì, dovrebbero essere ordinati correttamente quando interpretati come stringhe. Forse puoi mostrarci alcuni dati di esempio?

@yeti: Sfortunatamente no.
stefan,

Risposte:


5

Una soluzione 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

Spiegazione

  • Durante l'elaborazione del file, creiamo un array di array @h, ognuno dei suoi elementi è un riferimento di array [$F[-1],$_], con il primo elemento è il valore esadecimale da confrontare e il secondo elemento è l'intera riga.

  • In ENDblocco, utilizziamo la trasformazione di Schwartz :

    • Con ogni elemento di @h, crea un array anonimo, contiene l'intera riga ( $_->[1]il secondo elemento di ogni ref di array @h) e il valore esadecimale da confrontarehex($_->[0])]

    • Ordina sopra la base dell'array sul valore esadecimale $a->[1] <=> $b->[1]

    • Ottieni il primo elemento di ciascun riferimento dell'array nell'array ordinato, map { $_->[0] } quindi stampa il risultato.

Aggiornare

Con il suggerimento di @Joseph R, senza usare la Trasformazione di Schwartz:

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

Aggiornamento 2

Dopo aver letto il commento di stefan, penso che questo possa chiamare 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

+1 ma perché non solo print for sort { hex $a->[-1] <=> hex $b->[-1] } @h:? L' hexoperatore non è abbastanza costoso da giustificare uno Schwartziano, vero?
Joseph R.,

@JosephR .: Forse, ma uno Schwartzian è più flessibile e funziona in ogni caso. Penso che possiamo avere un'altra soluzione calcolando il valore esadecimale durante l'elaborazione, aggiornerò presto la mia risposta.
cuonglm,

Soluzione interessante. Non sapevo che questo modello avesse un nome: decora-decora-decora. Vedi il mio commento sopra.
Stefan,

@stefan: vedi la mia risposta aggiornata.
cuonglm,

@Gnouc: sì, il tuo secondo aggiornamento si qualifica definitivamente come diretto. la mia immaginazione iniziale.
Stefan,

6

Uso questi dati di esempio:

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

L'idea è di creare una nuova versione di questi dati con il campo di ordinamento in forma decimale. Cioè lo awkconverte, lo antepone a ciascuna riga, il risultato viene ordinato e come ultimo passo viene rimosso il campo aggiunto:

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

Il risultato è questo output:

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

1
Grazie, soluzione davvero interessante. Mi dispiace di non aver pubblicato la mia modifica in precedenza, segue un approccio simile usando cut + paste. Speravo in una soluzione più diretta, però ...
Stefan,

@stefan Cosa conta come "diretto"? La soluzione deve usare sort?
Joseph R.,

@Joseph “Ciò che conta come" diretto "?" È la domanda giusta. Fondamentalmente tutte le soluzioni finora (Hauke, Gnouc in basso e la mia) fanno qualcosa di simile: decodifica il valore esadecimale, collega il risultato alle linee, ordina per esso e rimuovilo. Stavo cercando qualcosa che non usasse il modello decora-decora-decora . Entrambe le soluzioni sono superiori alle mie, in quanto lavorano in una pipeline. Ho scelto questo perché personalmente preferirei usare awk (il martello più piccolo) di Perl per questo tipo di attività.
Stefan,

Ho spostato la mia scelta di una risposta al n. 3 di seguito, a causa del secondo aggiornamento di Gnouc.
Stefan,

1

Ingresso

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

Ordinamento di un liner

$ 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

Ordinamento passo dopo passo

Passaggio 1: aggiungere una nuova prima colonna con la rappresentazione decimale del numero esadecimale.

$ 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

Passaggio 2: ordinare le linee numericamente nel primo campo.

$ 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

Passaggio 3: rimuovere la prima colonna.

$ 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

0

adattato da: http://www.unix.com/302548935-post6.html?s=b4b6b3ed50b6831717f6429113302ad6

: Il file-to-Sort:

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

Comando:

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

Produzione:

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

- dove il toupper ($ 0) "aggiorna" le lettere minuscole in modo che ordinino per prime (non sei sicuro che sia necessario?)

Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.