urutkan berdasarkan nilai hex

14

Menggunakan coreutils sort, bagaimana saya bisa mengurutkan secara numerik dengan nilai heksadesimal (bidang)? Saya mengharapkan sesuatu di sepanjang garis

sort -k3,3x file_to_sort

namun demikian, xtidak ada.

Sunting: Solusi terbaik yang saya buat sejauh ini adalah:

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

di mana cut -d' ' -f3mengisolasi bidang pencarian (ini -k3,3- ini mungkin berbeda, tentu saja), dan bcapakah konversi ke desimal (memerlukan hex huruf besar, tanpa 0xawalan, cocok dengan kasus saya). Lalu saya bergabung, mengurutkan, dan membagi kolom.

Stefan
sumber
-k3,3? Anda memiliki hex hex yang menatap 0x dan semua dengan panjang yang sama? Tidak ada campuran huruf besar / kecil? Jika ya, mereka harus disortir saat ditafsirkan sebagai string. Mungkin Anda bisa menunjukkan beberapa contoh data kepada kami?
@yeti: Sayangnya, tidak.
Stefan
Permintaan fitur: lists.gnu.org/archive/html/coreutils/2017-08/msg00035.html
Ciro Santilli 新疆 改造 中心 法轮功 六四 事件

Jawaban:

5

Solusi di 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

Penjelasan

  • Saat memproses file, kami membuat array array @h, masing-masing elemennya adalah referensi array [$F[-1],$_], dengan elemen pertama adalah nilai hex untuk membandingkan, dan elemen kedua adalah seluruh baris.

  • Dalam ENDblok, kami menggunakan transformasi Schwartzian :

    • Dengan setiap elemen @h, buat array anonim, berisi seluruh baris ( $_->[1]elemen kedua dari setiap referensi array @h) dan nilai hex untuk membandingkanhex($_->[0])]

    • Sortir basis array di atas pada nilai hex $a->[1] <=> $b->[1]

    • Dapatkan elemen pertama dari setiap referensi array dalam array yang diurutkan map { $_->[0] } kemudian cetak hasilnya.

Memperbarui

Dengan saran @Joseph R, tanpa menggunakan Schwartzian Transform:

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

Perbarui 2

Setelah membaca komentar Stefan, saya pikir ini dapat menghubungi 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
cuonglm
sumber
+1 tetapi mengapa tidak hanya print for sort { hex $a->[-1] <=> hex $b->[-1] } @h:? The hexoperator adalah hampir tidak cukup mahal untuk menjamin Schwartzian, bukan?
Joseph R.
@ JosephR .: Mungkin, tetapi seorang Schwartzian lebih fleksibel dan berfungsi dalam semua kasus. Saya pikir kita dapat memiliki solusi lain dengan menghitung nilai hex saat memproses, akan segera memperbarui jawaban saya.
cuonglm
Solusi keren Tidak tahu pola ini memiliki nama: decorate-sort-undecorate. Lihat komentar saya di atas.
Stefan
@stefan: lihat jawaban saya yang diperbarui.
cuonglm
@Gnouc: ya, Pembaruan ke-2 Anda secara kualifikasi memenuhi syarat sebagai wrt langsung. imajinasi awal saya.
Stefan
6

Saya menggunakan contoh data ini:

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

Idenya adalah untuk membuat versi baru dari data ini dengan mengurutkan bidang dalam bentuk desimal. Yaitu awkmengkonversinya, menambahkannya ke setiap baris, hasilnya diurutkan, dan sebagai langkah terakhir bidang yang ditambahkan dihapus:

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

Yang menghasilkan output ini:

4 jjk 7
5 hhf 25
2 ukr 9f
3 ezh ae
1 hdh d12
Hauke ​​Laging
sumber
1
Terima kasih, solusi yang sangat keren. Maaf saya tidak memposting edit saya sebelumnya, ini mengikuti pendekatan yang sama menggunakan cut + paste. Saya berharap untuk solusi yang lebih langsung ...
Stefan
@stefan Apa yang dianggap sebagai "langsung"? Apakah solusinya harus digunakan sort?
Joseph R.
@ Joseph "Apa yang dianggap sebagai" langsung "?" Adalah pertanyaan yang tepat. Pada dasarnya semua solusi sejauh ini (Hauke's, Gnouc's di bawah, dan milikku) melakukan hal yang serupa: Dekode nilai hex, lampirkan hasil ke garis, urutkan berdasarkan itu, dan hapus. Saya mencari sesuatu yang tidak menggunakan pola menghias-semacam-dekorasi . Kedua solusi lebih unggul dari tambang, dalam hal itu pekerjaan pipa. Saya memilih yang ini karena saya pribadi lebih suka menggunakan awk (palu yang lebih kecil) daripada Perl untuk tugas semacam ini.
Stefan
Saya telah memindahkan pilihan jawaban ke # 3 di bawah, karena pembaruan kedua Gnouc.
Stefan
1

Memasukkan

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

Menyortir satu 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

Menyortir langkah demi langkah

Langkah 1: Tambahkan kolom pertama baru dengan representasi desimal dari nomor hex.

$ 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

Langkah 2: Urutkan garis secara numerik pada bidang pertama.

$ 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

Langkah 3: Hapus kolom pertama.

$ 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
Arun Saha
sumber
0

diadaptasi dari: http://www.unix.com/302548935-post6.html?s=b4b6b3ed50b6831717f6429113302ad6

: file-to-sort:

6F993B
954B29
A23F2F
BFA91D
C68C15
8F322F
5A6D40
6D512C
9D9D63
B4B823
A0641C
A79716
A18518

Perintah:

awk '{printf("%050s\t%s\n", toupper($0), $0)}' file-to-sort | LC_COLLATE=C sort -k1,1 | cut -f2

Keluaran:

C68C15
BFA91D
B4B823
A79716
A23F2F
A18518
A0641C
9D9D63
954B29
8F322F
6F993B
6D512C
5A6D40

--di mana huruf kecil ($ 0) "upgrade" huruf kecil sehingga mereka akan mengurutkan pertama (tidak yakin itu perlu?)

r_alex_hall
sumber