
我正在嘗試 printf 一些我透過管道輸入的 unicode 程式碼
echo 0024 0025 | xargs -n1 echo # one code per line
| xargs printf '\u%s\n'
希望得到這個
$
%
但這就是我得到的
printf: missing hexadecimal number in escape
經過一番嘗試和錯誤,我實際上有兩個較小的問題,一種是有道理的,另一種似乎完全是個謎。
問題一:
printf '\u%s\n' 0024 0025
給我這個
-bash: printf: missing unicode digit for \u
\u0024
-bash: printf: missing unicode digit for \u
\u0025
問題2:
> # use built-in for $
> printf '\u0024\n'
$
> # use exe for $
> which printf
/usr/bin/printf
> /usr/bin/printf '\u0024\n'
$
> # now use built-in for %
> printf '\u0025\n'
%
> # but look what happens when we use exe for % !!!!
> /usr/bin/printf '\u0025\n'
/usr/bin/printf: invalid universal character name \u0025
(使用>
for以便您可以在輸出中$
看到)$
由於某些原因,有些字元可以使用 exe 版本,但有些字元則不能,儘管所有字元都可以使用內建 printf。
所以這裡有一個解決方法,如果不是問題#2,它會起作用(但可能比我最初的想法慢很多)
echo 0024 0025 | xargs -n1 echo # one item per line
| xargs -I {} printf '\u{}\n'
但由於問題#2,它只起了一半作用:
$ echo 0024 0025 | xargs -n1 echo | xargs -I {} printf '\u{}\n'
$
printf: invalid universal character name \u0025
($ 出來但 % 出現錯誤)
所以我想我的問題是:
- 有沒有辦法讓 printf 使用數字代碼,以便我可以運行 printf 一次,而不是每個參數運行一次-I
?
-我做錯了什麼printf
內建不介意,但printf
exe不喜歡,但只為%
而不是為$
?
答案1
為了避免雙重展開問題(\u
之前已處理過%s
),您可以使用%b
,至少在 Bash 中printf
:
printf '%b\n' \\u0024 \\u0025
您可以透過多種方式預處理輸入:
set 0024 0025
printf '%b\n' "${@/#/\\u}"
獨立式printf
,在 GNU coreutils 中實現,對 Unicode 字元規範有以下限制:
printf
解釋 ISO C 99 中引入的兩種字元語法: '\u
' 表示 16 位元 Unicode (ISO/IEC 10646) 字符,指定為四個十六進位數字呵呵, 和 '\U
' 表示 32 位元 Unicode 字符,指定為八個十六進位數字哈哈哈哈。printf
根據LC_CTYPE
區域設定輸出 Unicode 字元。此語法無法指定 U+0000…U+009F、U+D800…U+DFFF 範圍內的 Unicode 字符,U+0024 ($)、U+0040 (@) 和 U+0060 (`) 除外。
這解釋了為什麼你不能%
以這種方式生產。
答案2
標準printf
實用程式不支援\uxxxx
轉義序列,請參閱:https://pubs.opengroup.org/onlinepubs/9699919799/utilities/printf.html
假設這可以工作取決於可能存在於一些實作中(例如內建ksh
)的擴展,但不能期望得到普遍支援。請參閱printf
標準文件。
另一個問題似乎是你假設調用
printf '\u%s\n' 123
會產生與呼叫相同的結果:
printf '\u123\n'
這不起作用,因為printf
逐個元素解析格式字串,但看不到預期的格式字串。
因此,即使您正在用來bash
執行腳本,\uxx
如果後面跟著兩個十六進制數字並且轉義序列按字面意思出現在格式字串中,您也可能會期望反斜線轉義被擴展。如果您想擴展 4 個十六進位數字,則需要\Uxxxx
在格式字串中按字面意思進行。