为什么我使用此脚本收到错误“print_unicode:第 9 行:printf:缺少 \u Unicode 0187 的 unicode 数字”

为什么我使用此脚本收到错误“print_unicode:第 9 行:printf:缺少 \u Unicode 0187 的 unicode 数字”

我按照 shell 脚本编写了它们,以查看 Unicode 字符在我的终端上的样子。

#!/bin/bash

X=0

while [ $X -lt 65536 ]; do
    HEX=`bc <<< "obase=16; $X"`
    HEX="0x${HEX}"
    UCODENAME=`printf "%0*x\n" 4 $HEX`
    UCODECHAR=`printf "\u%0*x\n" 4 $HEX`
    echo -e "Unicode ${UCODENAME} = ${UCODECHAR}"
    X=$((X + 1))
done

当我运行脚本时,我收到以下输出:

print_unicode: line 9: printf: missing unicode digit for \u
Unicode 0188 = ƈ

第二行正是我正在寻找的。

我确实尝试严格使用printf以消除错误。

#!/bin/bash

X=0

while [ $X -lt 65536 ]; do
    HEX=`bc <<< "obase=16; $X"`
    HEX="0x${HEX}"
    printf 'Unicode %0*x = \u%0*x\n' 4 $HEX 4 $HEX
    X=$((X + 1))
done

我得到以下输出:

print_unicode: line 8: printf: missing unicode digit for \u
Unicode 037f = \u037f

第二行不是我要找的,我仍然收到相同的错误消息。

我该如何修复这个错误?

奖励:对此有什么更优雅的解决方案?

答案1

你得到的错误的原因是:
内置 printf仅当它后面跟着一个实际数字时才理解\U(或):\u

$ printf '\U0021'
!

为了使其创建数字并转换它,需要一个两步 printf (需要一个双 \ 来传递双引号):

$ printf '%b' "$(printf '\\U%04X' 33)"
!

如你所愿:

$ printf '%b' "$(printf '\\u%0*X' 4 33)"
!

这也有效:

$ printf '%b' "$(printf '\\U%0*X' 8 33)"
!

不需要使用 bc 告诉 bash 十六进制数字。
bash 可以很好地理解这一点:

$ a=$(( 0xdef )); echo $(( a + 1 ))
3568

获取数字的十六进制值printf就足够了:

$ printf '0x%06x' 3568
0x000df0

该循环可以简化为:

#!/bin/bash

cp=$((0x020))     len=6

for (( cp=32; cp<$((0x010000)); cp++)); do    
    Ucode="$(printf '%b' "$(printf '\\U%0*X' "$len" "$cp")")"
    printf 'Unicode U%0*x = %s\n' 4 "$cp" "$Ucode"
done

谨防从 0x20 到 0x010000 有很多行(~ 64k 行)。

我将 len 增加到 6,因为 UNICODE 的代码点最多可达 10FFFF。

当然,Ucode 的完整定义是这样的:

Ucode="$(printf '%b' "$(printf '\\U%0*X' $len "$cp")")"

cp请注意, dec=32 或 HEX=0x20 以下的代码点 ( ) 是控制字符。

即使代码适用于这样的代码点我也这样做不是推荐你和他们一起玩。

除了对于 UNICODE U0000,因为该值被分配给变量。

这打印\0

$ printf '%b' "$(printf '\\U%0*X' "6" "0")"

与 xxd 确认:

$ printf '%b' "$(printf '\\U%0*X' "6" "0")" | xxd
0000000: 00

警告:4.3 以下的 Bash 无法正确编码 utf-8 中 U0080 和 U00FF 之间的值。请使用 4.3 或 4.4 版本。

答案2

我不断尝试找到了解决方案。

#!/bin/bash

X=0

while [ $X -lt 65536 ]; do
    HEX=`bc <<< "obase=16; $X"`
    HEX="0x${HEX}"
    UCODE=`printf "%0*x\n" 4 $HEX`
    printf "Unicode ${UCODE} = \u${UCODE}\n"
    X=$((X + 1))
done                                                        

我想到以这种方式尝试 printf: https://stackoverflow.com/questions/5947742/how-to-change-the-output-color-of-echo-in-linux

我仍然愿意看到更优雅的解决方案。

答案3

您可以用不同的方式执行此操作(因为 bash 似乎忽略uin周围的转义反斜杠"\u"):

#!/bin/bash

X=0

while [ $X -lt 65536 ]; do
    HEX=$(bc <<< "obase=16; $X")
    HEX="0x${HEX}"
    UCODENAME=$(printf "%0*x\n" 4 $HEX)
    UCODECHAR="\\u$(printf "%0*x" 4 $HEX)"
    echo -e "Unicode ${UCODENAME} = ${UCODECHAR}"
    X=$((X + 1))
done

当然,该脚本仍然是特定于 bash 的。其他一些评论:

  • 大多数人会建议使用$(and)而不是 back-tics。
  • bashprintf可以直接打印 Unicode(不需要 echo)。
  • 额外的printfforUCODECHAR是多余的

消除冗余:

#!/bin/bash

X=0

while [ $X -lt 65536 ]; do
    HEX=$(bc <<< "obase=16; $X")
    HEX="0x${HEX}"
    UCODENAME=$(printf "%0*x\n" 4 $HEX)
    UCODECHAR="\\u${UCODENAME}"
    echo -e "Unicode ${UCODENAME} = ${UCODECHAR}"
    X=$((X + 1))
done

相关内容