Chuyển đổi cơ sở BASH từ thập phân sang hex


29

Trong Bash, làm thế nào để chuyển đổi cơ sở từ thập phân sang cơ sở khác, đặc biệt là hex. Có vẻ dễ đi theo con đường khác:

$ echo $((16#55))
85

Với tìm kiếm trên web, tôi đã tìm thấy một tập lệnh thực hiện thao tác toán học và ký tự để thực hiện chuyển đổi và tôi có thể sử dụng nó như một hàm, nhưng tôi đã nghĩ rằng bash sẽ có chuyển đổi cơ sở tích hợp sẵn - Phải không?


Câu trả lời:


35

Với bash(hoặc bất kỳ shell nào, miễn là printflệnh có sẵn (một lệnh POSIX tiêu chuẩn thường được xây dựng trong các shell)):

printf '%x\n' 85

Với zsh, bạn cũng có thể làm:

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

Điều đó làm việc cho các cơ sở từ 2 đến 36 (với 0-9a-ztrường hợp không nhạy cảm như các chữ số).

Với ksh93, bạn có thể sử dụng:

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

Mà hoạt động cho các cơ sở từ 2 đến 64 (với 0-9a-zA-Z@_các chữ số).

Với kshzsh, cũng có:

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

Mặc dù điều đó giới hạn ở các cơ sở lên tới 36 trong ksh88, zsh và pdksh và 64 trong ksh93.

Lưu ý rằng tất cả những số đó được giới hạn ở kích thước của các longsố nguyên trên hệ thống của bạn ( intvới một số vỏ). Đối với bất cứ điều gì lớn hơn, bạn có thể sử dụng bchoặc dc.

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

Với các cơ sở được hỗ trợ nằm trong khoảng từ 2 đến một số số theo yêu cầu của POSIX tối thiểu là 99. Đối với các cơ sở lớn hơn 16, các chữ số lớn hơn 9 được biểu thị dưới dạng số thập phân 0 đệm cách nhau.

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

Hoặc tương tự với dc(đã bctừng (và vẫn còn trên một số hệ thống) một trình bao bọc xung quanh dc):

$ echo 30o123456p | dc
 04 17 05 06

Cảm ơn. Chính xác những gì tôi đang tìm kiếm. (Và đơn giản đến đáng xấu hổ.)
Dave Rove

Điều gì nếu bạn muốn làm một cơ sở tùy ý như bạn có thể chỉ định với #?
flarn2006

@ flarn2006. Với các bashnội trang, bạn có thể nhập số trong bất kỳ cơ sở nào, nhưng không xuất ra bất kỳ cơ sở nào ngoài 8, 10 và 16. Đối với các cơ sở khác, bạn cần một vỏ khác như zshhoặc kshhoặc sử dụng bc/dc.
Stéphane Chazelas

1
@ StéphaneChazelas Thật sao? Điều đó thật kỳ lạ. Có vẻ như họ quá lười biếng để lập trình theo cú pháp cho nó hoặc một cái gì đó; không có cách nào ý tưởng xuất ra trong bất kỳ căn cứ nào đã không xuất hiện trong đầu họ nếu họ thực hiện nhập liệu.
flarn2006

alias hex="printf '%x\n'"
mwfearnley

5

Sử dụng printf:

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

Để gán giá trị cho một biến sử dụng thay thế lệnh:

$ x=$( printf "%x" 85 ) ; echo $x
55

4
Hoặc, sử dụng -vtùy chọn cho bản in dựng sẵn:printf -v foo "%d" $((16#BEEF)); echo $foo
glenn jackman

@Glenn Sử dụng các tùy chọn không chuẩn (như -v) là không cần thiết ở đây; Tôi sẽ tránh nó.
Janis

3
-vsẽ tránh ngã ba và đường ống (trong bash, không phải ksh93 sẽ không rẽ nhánh ở đây như printfđược xây dựng). Lưu ý rằng đó $((16#55))cũng không phải là tiêu chuẩn.
Stéphane Chazelas

@ StéphaneChazelas, đợi một chút. Bạn đang nói rằng ksh93 không rẽ nhánh x=$(some_builtin)?
glenn jackman

1
@glennjackman, vâng, nó chỉ dùng để thực hiện các lệnh bên ngoài.
Stéphane Chazelas

2

Sử dụng thay thế Mở rộng Số học tích hợp có trong tất cả các vỏ tuân thủ POSIX - ngày nay khá phổ biến.

$ echo $((0xbc))
188

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

THẬN TRỌNG: Đặc biệt trong ví dụ trước, việc mở rộng có thể gây ra kết quả không mong muốn - các chữ số hex trong biến 'hex' phải tạo thành hằng số hex hợp pháp, nếu không có khả năng xảy ra thông báo lỗi. ví dụ: nếu 'hex' là '0xdead', thì việc mở rộng số học sẽ trở thành 0x0xdead, không thể hiểu là một hằng số. Tất nhiên, trong trường hợp đó, việc mở rộng số học $ (($ hex)) sẽ thực hiện thủ thuật. Nó được để lại như một bài tập cho người đọc để tạo mẫu xử lý chuỗi con đơn giản phù hợp sẽ loại bỏ tiền tố '0x' tùy chọn.


4
Bạn đang làm chính xác những gì OP đã làm trong ví dụ của mình; Anh ta đang tìm kiếm hoạt động ngược lại .
Thomas Guyot-Sionnest

0

Bạn có thể sử dụng thư viện awk Velour :

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

Hoặc là:

$ velour -n 'print n_baseconv(ARGV[1], 10, 16)' 15
F
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.