Take the 2-minute tour ×
Unix & Linux Stack Exchange is a question and answer site for users of Linux, FreeBSD and other Un*x-like operating systems.. It's 100% free, no registration required.

Using coreutils sort, how can I sort numerically by a hexadecimal value (field)? I was expecting something along the lines of

sort -k3,3x file_to_sort

however, such an x does not exist.

Edit: Best solution I came up with so far is:

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

where the cut -d' ' -f3 isolates the search field (this is -k3,3 — this may vary, of course), and bc does conversion to decimal (requires upper-case hex, without 0x prefix, matching my case). Then I join, sort, and split columns.

share|improve this question
    
-k3,3? You have hex nubers staring with 0x and all of the same length? No mix of upper/lowercase? If yes, they should sort right when interpreted as strings. Maybe you can show us some example data? –  yeti Jun 29 at 14:43
    
@yeti: Unfortunately, no. –  stefan Jun 29 at 14:45

2 Answers 2

up vote 3 down vote accepted

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
share|improve this answer
    
+1 but why not just : print for sort { hex $a->[-1] <=> hex $b->[-1] } @h? The hex operator is hardly expensive enough to warrant a Schwartzian, isn't it? –  Joseph R. Jun 30 at 13:06
    
@JosephR.: Maybe, but a Schwartzian is more flexible and work in all case. I think we can have another solution by compute the hex value while processing, will update my answer soon. –  cuonglm Jun 30 at 13:13
    
Cool solution. Did not know this pattern had a name: decorate-sort-undecorate. See my comment above. –  stefan Jun 30 at 16:32
    
@stefan: see my updated answer. –  cuonglm Jun 30 at 16:59
    
@Gnouc: yes, your 2nd Update definitively qualifies as direct wrt. my initial imagination. –  stefan Jul 7 at 19:57

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
share|improve this answer
    
Thanks, pretty cool solution. Sorry that I did not post my edit earlier, it follows a similar approach using cut+paste. I was hoping for a more direct solution though... –  stefan Jun 29 at 15:00
    
@stefan What counts as "direct"? Does the solution have to use sort? –  Joseph R. Jun 29 at 15:22
    
@Joseph “What counts as "direct"?” is the right question. Basically all solutions so far (Hauke's, Gnouc's below, and mine) do something similar: Decode the hex value, attach result to the lines, sort by it, and remove it. I was looking for something not using the decorate-sort-undecorate pattern. Both solutions are superior to mine, in that tey work in a pipeline. I've chosen this one because I'd personally rather use awk (the smaller hammer) than Perl for this kind of task. –  stefan Jun 30 at 16:32
    
I have moved my choice of an answer to #3 below, because of Gnouc's second update. –  stefan Jul 7 at 19:58

Your Answer

 
discard

By posting your answer, you agree to the privacy policy and terms of service.

Not the answer you're looking for? Browse other questions tagged or ask your own question.