16進値でソート

16進値でソート

coreutilsを使用してsort16進値(フィールド)に基づいて数値をソートする方法は?こんなことを期待していた

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があります)、bc10進数に変換します(大文字と0x小文字を一致させるにはプレフィックスなしで大文字の16進数が必要です)。次に、列を連結し、ソートして分割します。

最小サンプル入力:

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

期待される出力(hex3番目の列でソートされたファイル):

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

アイデアは、10進形式のソートフィールドを使用してこのデータの新しいバージョンを生成することです。つまり、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これはGNUawk機能を想定していますstrtonum()

答え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],$_]、最初の要素は比較する16進値であり、2番目の要素は行全体です。

  • END私たちが使うブロックではシュワルツ変換:

    • 各要素を使用して、@h行全体($_->[1]各配列参照の2番目の要素@h)と比較する16進値を含む匿名配列を作成します。hex($_->[0])]

    • 16進値に基づいて上記の配列を並べ替えます。$a->[1] <=> $b->[1]

    • ソートされた配列から各配列参照の最初の要素を取得し、map { $_->[0] }結果を印刷します。

修正する

@Joseph Rの提案に基づいて:

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

アップデート2

Schwartzian変換を使用せずにStefanのコメントを読んだ後:

$ 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:16進数の10進数表現を含む新しい最初の列を追加します。

$ 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 -g16進値を並べ替えることができます。0xプレフィックスが必要です。

awk '{ $3 = "0x" $3; print }' sample.txt |
 sort -g -k3 |
 awk '{ $3 = gensub(/^0x/, "", 1, $3); print }'
  1. 0x3列目に追加する前に
  2. 汎用数値ソートオプションを使用して3番目の列に基づいてソート
  3. 0x3番目の列から削除

関連情報