ฉันจะพิมพ์อักขระ ASCII ด้วยจุดรหัสที่แตกต่างใน Bash ได้อย่างไร


12

ในตาราง ASCII มีอักขระ 'J' อยู่ซึ่งมีจุดรหัสในระบบตัวเลขต่าง ๆ :

Oct   Dec   Hex   Char
112   74    4A    J

มันเป็นไปได้ที่จะพิมพ์ถ่านนี้โดยจุดรหัสเลขฐานแปดโดยการพิมพ์ หรือprintf '\112' echo $'\112'ฉันจะพิมพ์ตัวละครเดียวกันโดยนำเสนอทศนิยมและเลขฐานสิบหกจุดได้อย่างไร?


คำตอบ:



6

ด้วยzsh:

$ printf '\x4a\n' # Hex
J
$ printf "\\$(([##8]74))\n" # Dec
J

ในการรับตัวอักษร (ในชุดอักขระปัจจุบัน) จากจุดโค้ด Unicode:

$ printf '\U1F42E\n' # Hex
🐮
$ printf "\\U$(([##16]128046))\n" # Dec
🐮

คำตอบได้โปรดวิธีการพิมพ์ใบหน้านี้โดยใช้รหัสฐานสิบหก 'f0 9f 90 ae'
viavad


6

โดยทั่วไปเชลล์สามารถเข้าใจตัวเลขฐานสิบหกฐานสิบและทศนิยมในตัวแปรหากพวกเขาถูกกำหนดเป็นintegers:

$ declare -i v1 v2 v3 v4 v5 v6 v7
$ v1=0112
$ v2=74
$ v3=0x4a
$ v4=8#112
$ v5=10#74
$ v6=16#4a
$ v7=18#gg
echo "$v1 $v2 $v3 $v4 $v5 $v6 $v7"
74 74 74 74 74 74 304

หรือพวกเขาเป็นผลมาจาก "การขยายตัวทางคณิตศาสตร์":

$ : $(( v1=0112, v2=74, v3=0x4a, v4=8#112, v5=10#74, v6=16#4a, v7=18#gg ))
$ echo "$v1 $v2 $v3 $v4 $v5 $v6 $v7"
74 74 74 74 74 74 304

ดังนั้นคุณเพียงแค่ต้องการพิมพ์อักขระที่เป็นค่าตัวแปร
แต่นี่เป็นวิธีที่เป็นไปได้สองวิธี:

$ var=$((0x65))
$ printf '%b\n' "\\$(printf '0%o' "$var")"
e

$ declare -i var
$ var=0x65; printf '%b\n' "\U$(printf '%08x' "$var")"
e

จำเป็นต้องใช้ printf สองอันอันหนึ่งเพื่อแปลงค่าให้เป็นสตริงเลขฐานสิบหกและที่สองเพื่อพิมพ์อักขระจริง

ส่วนที่สองจะพิมพ์จุด UNICODE ใด ๆ (หากตั้งค่าคอนโซลของคุณอย่างถูกต้อง)
ตัวอย่างเช่น:

$ var=0x2603; printf '%b\n' "\U$(printf '%08x' "$var")"

มนุษย์หิมะ

ตัวละครที่มี UTF-8 เป็นตัวแทนมีf0 9f 90 ae 0x1F42Eค้นหาcow face site:fileformat.infoเพื่อรับมัน :

$ var=0x1F42F; printf '%b\n' "\U$(printf '%08x' "$var")"
🐮

หมายเหตุ : มีปัญหาเกี่ยวกับวิธี UNICODE ในการทุบตีก่อน 4.3 (แก้ไขในรุ่นนั้นและสูงกว่า) ตัวละครระหว่าง UNICODE คะแนน 128 และ 255 (ทศนิยม) อาจพิมพ์ไม่ถูกต้อง


อ้างอิง

ภายในวรรคสี่PARAMETERSในman bash:

หากตัวแปรมีชุดแอตทริบิวต์จำนวนเต็มค่าจะถูกประเมินเป็นนิพจน์ทางคณิตศาสตร์แม้ว่าจะไม่ได้ใช้การขยาย $ ((... )) (ดูที่การขยายตัวทางคณิตศาสตร์ด้านล่าง)

ภายใน "การประเมินผล ARITHMETIC" ในman bash:

ค่าคงที่ที่มี 0 นำหน้าจะถูกตีความเป็นตัวเลขฐานแปด ส่วนนำ 0x หรือ 0X หมายถึงเลขฐานสิบหก มิฉะนั้นตัวเลขจะอยู่ในรูปแบบ [base #] n โดยที่ตัวเลือกพื้นฐานคือตัวเลขทศนิยมระหว่าง 2 ถึง 64 ที่แสดงถึงฐานเลขคณิตและ n คือตัวเลขในฐานนั้น หากไม่ระบุ base # ระบบจะใช้ฐาน 10 ตัวเลขที่มากกว่า 9 แสดงด้วยตัวอักษรตัวเล็กตัวอักษรตัวพิมพ์ใหญ่ @ และ _ ในลำดับนั้น หากฐานมีค่าน้อยกว่าหรือเท่ากับ 36 ตัวอักษรตัวพิมพ์เล็กและตัวพิมพ์ใหญ่อาจถูกใช้แทนกันเพื่อแสดงตัวเลขระหว่าง 10 ถึง 35


@ StéphaneChazelasดี codepoint ไม่ได้ (เสมอ) ค่าไบต์ Bash (ในรุ่นก่อน 4.3) ให้ค่าไบต์ของจุดรหัส นั่นคือ: อักขระé(Octal: 351, Dec: 233, Hex: 0xE9) ถูกพิมพ์อย่างไม่ถูกต้องprintf '\351'เนื่องจากมันพิมพ์ค่าไบต์เป็น0xE9เสมอ สำหรับเทอร์มินัลที่มีการเข้ารหัสISO-8859-1(และลูกพี่ลูกน้อง) ที่อาจใช้งานได้ แต่ในเทอร์มินัลที่เข้ารหัส utf-8 ค่าไบต์ของ0xE9ควรจะปรากฏเป็น ต่อ ....
ไอแซค

@ StéphaneChazelasฉันไม่ใช่คนแรกที่สังเกตเห็นและค้นหา "bash 4.2 encodes ไม่ถูกต้อง" สำหรับตัวอย่างหนึ่ง มันได้รับการแก้ไขจากทุบตี 4.3 และสูงกว่า
ไอแซค

ตกลง. ฉันเห็นสิ่งที่คุณหมายถึงตอนนี้ (ฉันกำลังทดสอบกับ 4.3 ตามคำตอบของคุณรุ่นก่อนหน้า) โปรดทราบว่ามันเป็นเพียง bash-4.2, bash-4.1 ไม่รองรับ\u(ซึ่งมาจาก zsh)
Stéphane Chazelas


0

คุณสามารถใช้ไลบรารี POSIX Awk stdlib :

$ awklib 'BEGIN {print str_chr(74)}'
J

$ awklib 'BEGIN {print str_chr(+base_conv("4A", 16, 10))}'
J

$ awklib 'BEGIN {print str_chr(+base_conv(112, 8, 10))}'
J

$ awklib 'BEGIN {print str_chr(+base_conv(1001010, 2, 10))}'
J

0

หากคุณมีรายการหมายเลขที่จะแปลงและต้องการหลีกเลี่ยงการเรียกใช้ฟังก์ชันและสร้าง subshell สำหรับอักขระแต่ละตัวคุณสามารถกำหนดชุด ASCII ล่วงหน้า:

ascii=$(for x in {0..9} {A..F}; do for y in {0..9} {A..F}; do echo -ne "\x$x$y"; done; done)

โปรดทราบว่าตัวกรอง null ไม่รวมดังนั้นถ่านทุกตัวจะถูกชดเชยด้วย 1

จากนั้นใช้บางสิ่งเช่นนี้ (สมมติว่า 1 หมายเลขต่อบรรทัด):

while read c; do out+="${ascii:$c-1:1}"; done <<< "$in"
echo "$out"

0

นี่คือการแปลงทั้งหมดที่ใช้printf:

printf "%o" "'J" # 112 (oct)
printf "%d" "'J" # 74 (dec)
printf "%x" "'J" # 4a (hex)

printf '\112' # J (oct)
printf "\x$(printf %x 74)" # J (dec, requires double conversion)
printf '\x4a' # J (hex)
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.