我正在尝试 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
在格式字符串中按字面意思进行。