Bash

如何在 Bash 中通過不同的程式碼點列印 ASCII 字元?

  • June 9, 2021

在 ASCII 表中,存在“J”字元,它在不同的數字系統中有程式碼點:

Oct   Dec   Hex   Char
112   74    4A    J

可以通過列印 printf '\112'或通過八進制程式碼點列印此字元echo $'\112'。如何通過十進制和十六進制程式碼點表示列印相同的字元?

十六進制:

printf '\x4a'

十二月:

printf "\\$(printf %o 74)"

十六進制的替代品:-)

xxd -r <<<'0 4a'

一般來說,shell 可以理解變數中的十六進制、八進制和十進制數字,只要它們被定義為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 ae0x1F42E. 搜尋cow face site:fileformat.info得到

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

注意:對於 4.3 之前的 bash(在該版本及更高版本中已更正),UNICODE 方式存在問題,UNICODE 點 128 和 255(十進制)之間的字元可能列印不正確。


參考

PARAMETERS裡面的第四段man bash

如果變數具有其整數屬性集,則即使不使用 $((…)) 擴展,也會將 value 評估為算術表達式(請參閱下面的算術擴展)。

在“算術評估”中man bash

以 0 開頭的常量被解釋為八進制數。前導 0x 或 0X 表示十六進制。否則,數字採用形式

$$ base# $$n,其中可選基數是 2 到 64 之間的十進制數,表示算術基數,n 是該基數中的數字。如果省略 base#,則使用基數 10。大於 9 的數字依次用小寫字母、大寫字母、@ 和 _ 表示。如果 base 小於或等於 36,則可以互換使用小寫和大寫字母來表示 10 到 35 之間的數字。

引用自:https://unix.stackexchange.com/questions/311904