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 comparehex($_->[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