按十六进制值排序

按十六进制值排序

使用 coreutils sort,如何按十六进制值(字段)进行数字排序?我期待着类似的事情

sort -k3,3x file_to_sort

然而,这样的情况x并不存在。

编辑:到目前为止我想出的最佳解决方案是:

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

其中cut -d' ' -f3隔离搜索字段(当然-k3,3,这可能会有所不同),并bc转换为十进制(需要大写十六进制,没有0x前缀,与我的情况匹配)。然后我连接、排序和拆分列。

最小样本输入:

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

预期输出(按hex第三列排序的文件):

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

答案1

我使用这个示例数据:

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

这个想法是使用十进制形式的排序字段创建该数据的新版本。即awk1 对其进行转换,将其添加到每一行的前面,对结果进行排序,最后一步删除添加的字段:

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

其结果是这样的输出:

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

1 这里假设 GNUawkstrtonum()功能。

答案2

解决方案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

解释

  • 在处理文件时,我们创建一个数组的数组@h,它的每个元素都是一个数组引用[$F[-1],$_],第一个元素是要比较的十六进制值,第二个元素是整行。

  • END块中,我们使用施瓦茨变换:

    • 使用 的每个元素@h,创建一个匿名数组,包含整行($_->[1]每个数组 ref 中的第二个元素@h)和要比较的十六进制值hex($_->[0])]

    • 根据十六进制值对上面的数组进行排序$a->[1] <=> $b->[1]

    • 获取排序数组中每个数组 ref 的第一个元素,map { $_->[0] }然后打印结果。

更新

根据@Joseph R 的建议:

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

更新2

阅读 Stefan 的评论后,不使用 Schwartzian 变换:

$ 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

答案3

输入

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

排序一个班轮

$ 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

逐步排序

步骤 1:添加新的第一列,其中包含十六进制数的十进制表示形式。

$ 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

步骤 2:按数字对第一个字段中的行进行排序。

$ 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

步骤 3:删除第一列。

$ 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

答案4

sort -g可以对十六进制值进行排序。需要注意的是,它需要0x前缀。

awk '{ $3 = "0x" $3; print }' sample.txt |
 sort -g -k3 |
 awk '{ $3 = gensub(/^0x/, "", 1, $3); print }'
  1. 添加0x到第三列之前
  2. 使用通用数字排序选项按第三列排序
  3. 0x从第三列删除

相关内容