Konversi basis BASH dari desimal ke hex

29

Di Bash, bagaimana seseorang melakukan konversi basis dari desimal ke basis lain, terutama hex. Tampaknya mudah untuk pergi ke arah lain:

$ echo $((16#55))
85

Dengan pencarian web, saya menemukan skrip yang melakukan manipulasi matematika dan karakter untuk melakukan konversi, dan saya bisa menggunakannya sebagai fungsi, tetapi saya akan berpikir bahwa bash sudah memiliki konversi basis bawaan - melakukannya?

Dave Rove
sumber
stackoverflow.com/questions/378829/…
Ciro Santilli 新疆 改造 中心 法轮功 六四 事件 事件

Jawaban:

35

Dengan bash(atau shell apa pun, asalkan printfperintah tersedia (perintah POSIX standar yang sering dibuat di shell)):

printf '%x\n' 85

Dengan zsh, Anda juga bisa melakukan:

dec=85
hex=$(([##16]dec))

Itu berfungsi untuk basis dari 2 hingga 36 (dengan 0-9a-zcase case-digit).

Dengan ksh93, Anda dapat menggunakan:

dec=85
base54=$(printf %..54 "$dec")

Yang berfungsi untuk basis dari 2 hingga 64 (dengan 0-9a-zA-Z@_sebagai digit).

Dengan kshdan zsh, ada juga:

$ typeset -i34 x=123; echo "$x"
34#3l

Meskipun itu terbatas pada basis hingga 36 di ksh88, zsh dan pdksh dan 64 di ksh93.

Perhatikan bahwa semua itu terbatas pada ukuran longbilangan bulat di sistem Anda ( intdengan beberapa shell). Untuk yang lebih besar, Anda bisa menggunakan bcatau dc.

$ echo 'obase=16; 9999999999999999999999' | bc
21E19E0C9BAB23FFFFF
$ echo '16o 9999999999999999999999 p' | dc
21E19E0C9BAB23FFFFF

Dengan pangkalan yang didukung mulai dari 2 hingga beberapa angka yang diperlukan oleh POSIX harus setidaknya setinggi 99. Untuk pangkalan yang lebih besar dari 16, digit lebih besar dari 9 direpresentasikan sebagai angka desimal 0-empuk yang dipisahkan oleh ruang.

$ echo 'obase=30; 123456' | bc
 04 17 05 06

Atau sama dengan dc( bcdulu (dan masih ada pada beberapa sistem) pembungkus dc):

$ echo 30o123456p | dc
 04 17 05 06
Stéphane Chazelas
sumber
Terima kasih. Persis apa yang saya cari. (Dan sangat memalukan.)
Dave Rove
Bagaimana jika Anda ingin melakukan basis sewenang-wenang seperti yang dapat Anda tentukan #?
flarn2006
@ flarn2006. Dengan bashbuiltin, Anda dapat memasukkan angka di pangkalan apa pun, tetapi tidak membuat pangkalan di pangkalan apa pun selain 8, 10 dan 16. Untuk pangkalan lainnya, Anda perlu shell seperti zshatau kshatau digunakan bc/dc.
Stéphane Chazelas
1
@ StéphaneChazelas Benarkah? Agak aneh. Sepertinya mereka terlalu malas memprogram sintaks untuk itu atau sesuatu; tidak mungkin ide keluaran di basis apa pun tidak terlintas dalam pikiran mereka jika mereka menerapkan input.
flarn2006
alias hex="printf '%x\n'"
mwfearnley
5

Gunakan printf:

$ printf "%d %x\n" $((16#55)) $((10#85))
85 55

Untuk menetapkan nilai pada substitusi, gunakan perintah:

$ x=$( printf "%x" 85 ) ; echo $x
55
Janis
sumber
4
Atau, gunakan -vopsi untuk printf bawaan:printf -v foo "%d" $((16#BEEF)); echo $foo
glenn jackman
@ Glenn Menggunakan opsi non-standar (seperti -v) tidak perlu di sini; Saya akan menghindarinya.
Janis
3
-vakan menghindari garpu dan pipa (dalam bash, bukan ksh93 yang tidak akan bercabang di sini seperti printfyang dibangun). Catatan yang $((16#55))tidak standar juga.
Stéphane Chazelas
@ StéphaneChazelas, tunggu sebentar. Apakah Anda mengatakan bahwa ksh93 tidak menggunakan garpu x=$(some_builtin)?
glenn jackman
1
@glennjackman, ya, itu hanya garpu untuk mengeksekusi perintah eksternal.
Stéphane Chazelas
2

Gunakan substitusi Ekspansi Aritmatika bawaan yang ada di semua kerangka yang sesuai dengan POSIX - yang cukup universal akhir-akhir ini.

$ echo $((0xbc))
188

dan

$ hex=dead
$ dec=$((0x$hex))
$ echo $dec
57005

PERHATIAN: Khususnya dalam contoh terakhir ekspansi dapat menyebabkan hasil yang tidak diharapkan - digit hex dalam variabel 'hex' harus membentuk konstanta hex legal, jika tidak terjadi pesan kesalahan yang berpotensi tidak jelas. misal jika 'hex' adalah '0xdead', ekspansi aritmatika akan menjadi 0x0xdead, yang tidak dapat diartikan sebagai konstanta. Tentu saja, dalam hal ini ekspansi aritmatika $ (($ hex)) akan melakukan trik. Ini dibiarkan sebagai latihan bagi pembaca untuk membuat pencocokan pola pemrosesan substring sederhana yang akan menghapus awalan '0x' opsional.

Mark van der Pol
sumber
4
Anda melakukan hal yang persis sama dengan OP dalam contohnya; dia mencari operasi sebaliknya .
Thomas Guyot-Sionnest
0

Anda dapat menggunakan perpustakaan Velk awk :

$ velour -n 'print n_baseconv(15, 10, 16)'
F

Atau:

$ velour -n 'print n_baseconv(ARGV[1], 10, 16)' 15
F
Steven Penny
sumber