sort by hex value

I use this example data:

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

The idea is to create a new version of this data with the sort field in decimal form. I.e. awk converts it, prepends it to each line, the result is sorted, and as last step the added field is removed:

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

Which results in this output:

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

A solution 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

Explanation

  • While processing file, we create an array of array @h, each of its element is an array reference [$F[-1],$_], with first element is the hex value to compare, and the second element is the whole line.

  • In END block, we use Schwartzian transform:

    • With each element of @h, create an anonymous array, contains the whole line ( $_->[1] the second element of each array ref in @h ) and the hex value to compare hex($_->[0])]

    • Sort above array base on the hex value $a->[1] <=> $b->[1]

    • Get the first element of each array ref in sorted array map { $_->[0] } then print the result.

Update

With @Joseph R's suggestion, without using Schwartzian Transform:

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

Update 2

After reading stefan's comment, I think this can call 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

Input

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

Sorting one 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

Sorting step by step

Step 1: Add a new first column with the decimal representation of the hex number.

$ 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

Step 2: Sort the lines numerically on the first field.

$ 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

Step 3: Remove the first column.

$ 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

Tags:

Coreutils

Sort