แปลงฐาน BASH จากฐานสิบเป็นฐานสิบหก


29

ในทุบตีวิธีการหนึ่งจะทำแปลงฐานจากทศนิยมเพื่อฐานอีกหกเหลี่ยมโดยเฉพาะอย่างยิ่ง ดูเหมือนจะเป็นวิธีที่ง่ายกว่า:

$ echo $((16#55))
85

ด้วยการค้นเว็บฉันพบสคริปต์ที่ใช้การคำนวณทางคณิตศาสตร์และตัวละครเพื่อทำการแปลงและฉันสามารถใช้มันเป็นฟังก์ชั่นได้ แต่ฉันคิดว่าทุบตีจะมีการแปลงฐานในตัวแล้ว - ทำมัน?


คำตอบ:


35

ด้วยbash(หรือเชลล์ใด ๆ , ให้printfคำสั่งพร้อมใช้งาน (คำสั่ง POSIX มาตรฐานมักจะสร้างขึ้นในเชลล์)):

printf '%x\n' 85

ด้วยzsh, คุณสามารถทำได้:

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

ใช้งานได้กับฐานตั้งแต่ 2 ถึง 36 (โดย0-9a-zไม่คำนึงถึงขนาดตัวพิมพ์เป็นตัวเลข)

ด้วยksh93คุณสามารถใช้:

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

ซึ่งใช้งานได้กับเบสตั้งแต่ 2 ถึง 64 (โดยใช้0-9a-zA-Z@_เป็นดิจิต)

ด้วยkshและzshยังมี:

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

แม้ว่าจะ จำกัด อยู่ที่ฐานสูงสุด 36 ใน ksh88, zsh และ pdksh และ 64 ใน ksh93

โปรดทราบว่าสิ่งเหล่านั้นถูก จำกัด ไว้ที่ขนาดของlongจำนวนเต็มในระบบของคุณ ( intมีบางเชลล์) สำหรับสิ่งที่ใหญ่กว่าคุณสามารถใช้หรือbcdc

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

ด้วยฐานที่รองรับตั้งแต่ 2 ถึงบางหมายเลขที่ POSIX ต้องการอย่างน้อยจะสูงถึง 99 สำหรับฐานที่มากกว่า 16 ตัวเลขที่มากกว่า 9 จะแสดงเป็นเลขฐานสิบ 0 เบาะที่คั่นด้วยช่องว่าง

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

หรือเหมือนกันกับdc( bcเคยเป็น (และยังคงอยู่ในบางระบบ) เสื้อคลุมรอบdc):

$ echo 30o123456p | dc
 04 17 05 06

ขอบคุณ สิ่งที่ฉันกำลังมองหา (และเรียบง่ายน่าอับอาย)
Dave Rove

เกิดอะไรขึ้นถ้าคุณต้องการจะทำฐานโดยพลการเช่นคุณสามารถระบุด้วย#?
flarn2006

@ flarn2006 ด้วยbashbuiltins คุณสามารถป้อนข้อมูลตัวเลขในฐานใด ๆ แต่ไม่ได้ผลลัพธ์ในฐานอื่น ๆ กว่า 8, 10 และ 16 สำหรับฐานอื่น ๆ ที่คุณจะต้องเปลือกอีกเหมือนzshหรือหรือการใช้งานksh bc/dc
Stéphane Chazelas

1
@ StéphaneChazelasจริงเหรอ? นั่นเป็นเรื่องแปลก ดูเหมือนว่าพวกเขาขี้เกียจเกินกว่าจะเขียนโปรแกรมในรูปแบบของมันหรือบางสิ่งบางอย่าง ไม่มีวิธีที่ความคิดในการแสดงผลในฐานใด ๆ ไม่ได้ข้ามความคิดของพวกเขาหากพวกเขาดำเนินการป้อนข้อมูล
flarn2006

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

5

ใช้ printf:

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

ในการกำหนดค่าให้กับการทดแทนคำสั่งตัวแปรให้ใช้:

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

4
หรือใช้-vตัวเลือกสำหรับ builtin printf:printf -v foo "%d" $((16#BEEF)); echo $foo
glenn jackman

@Glenn -vไม่จำเป็นต้องใช้ตัวเลือกที่ไม่ได้มาตรฐาน (เช่น) ฉันจะหลีกเลี่ยง
Janis

3
-vจะหลีกเลี่ยงการแยกและท่อ (ในทุบตีไม่ใช่ ksh93 ซึ่งจะไม่แยกที่นี่เหมือนในprintfตัว) โปรดทราบ$((16#55))ว่าไม่ได้มาตรฐานอย่างใดอย่างหนึ่ง
Stéphane Chazelas

@ StéphaneChazelasรอสักครู่ คุณกำลังพูดว่า ksh93 ไม่แยกx=$(some_builtin)ใช่หรือไม่?
เกล็นแจ็คแมน

1
@glennjackman ใช่มันใช้สำหรับการรันคำสั่งภายนอกเท่านั้น
Stéphane Chazelas

2

ใช้การทดแทนการขยายตัวทางคณิตศาสตร์ในตัวที่มีอยู่ในเชลล์ที่สอดคล้องกับ POSIX ทั้งหมด - ซึ่งค่อนข้างเป็นสากลในทุกวันนี้

$ echo $((0xbc))
188

และ

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

ข้อควรระวัง: โดยเฉพาะอย่างยิ่งในตัวอย่างสุดท้ายการขยายอาจทำให้เกิดผลลัพธ์ที่ไม่คาดคิด - ตัวเลขฐานสิบหกในตัวแปร 'ฐานสิบหก' ต้องสร้างค่าคงที่ฐานสิบหกตามกฎหมายมิฉะนั้นอาจเกิดข้อผิดพลาดที่ไม่ชัดเจน เช่นถ้า 'hex' เป็น '0xdead' การขยายเลขคณิตจะกลายเป็น 0x0xdead ซึ่งไม่สามารถตีความได้ว่าเป็นค่าคงที่ แน่นอนว่าในกรณีนี้การขยายเลขคณิต $ (($ hex)) จะใช้เคล็ดลับ มันเหลือเป็นแบบฝึกหัดสำหรับผู้อ่านเพื่อสร้างรูปแบบการประมวลผลสตริงย่อยแบบง่ายที่จะลบคำนำหน้า '0x' ที่เป็นทางเลือก


4
คุณกำลังทำสิ่งเดียวกันกับที่ OP ทำในตัวอย่างของเขา เขากำลังมองหาการดำเนินการย้อนกลับ
Thomas Guyot-Sionnest

โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.