ASCII 字符范围是从 0 到 127,在该范围内,awk 的带有 %c 格式说明符的 printf 输出一个字节的数据:
$ awk 'BEGIN{printf "%c", 97}'
a
$ awk 'BEGIN{printf "%c", 127}' | xxd
00000000: 7f
$ awk 'BEGIN{printf "%c", 127}' | xxd -b
00000000: 01111111
但对于大于 127 的值,它将打印出多个字节:
$ awk 'BEGIN{printf "%c", 128}' | xxd
00000000: c280
$ awk 'BEGIN{printf "%c", 128}' | xxd -b
00000000: 11000010 10000000
0xc280 的意义是什么?为什么 awk 输出该字符而不是 0x80?
答案1
这是UTF-8编码。 11000010开始一个双字节序列(前两位设置后跟一个清零位),有效位为00010000000(第一个字节的最后五位,第二个字节的最后六位),即128 。
AWK 输出此内容是因为您的语言环境设置为使用 UTF-8;您可以切换到非 UTF-8 语言环境来查看差异:
$ LC_ALL=C awk 'BEGIN{printf "%c", 128}' | xxd -b
00000000: 10000000
答案2
让 awk 打印出任意字节的一个技巧是,无论您的语言环境是 UTF8、POSIX 还是 C,都将 256 的大倍数添加到无符号字节条例值中,以使新数字高于0x10FFFF
Unicode 14 的限制规格
下面是如何在 gawk 字节模式下访问任意字节以打印出 UTF8 编码字符的演示。同样的方法也可以在 gawk unicode 模式下使用来访问任意字节:
gawk -e 'BEGIN { printf("%c",50000) }' | od -baxco -t dC
0000000 354 215 220
? 8d 90
8dec 0090
썐 ** **
106754 000220
-20-115-112
0000003
% gawk -b -e 'BEGIN { printf("%c%c%c",
(-20)+8^8,
(-115)+8^8,
(-112)+8^8) }' | od -baxco -t dC
0000000 354 215 220
? 8d 90
8dec 0090
썐 ** **
106754 000220
-20-115-112
0000003
% gawk -e 'BEGIN { printf("%c%c%c%c",\
\
0xAB+8^8, 0xBA+8^8, \
0xCA+8^8, 0xFE+8^8) }' \
| god --endian=big -baxco -t dCxI
0000000 253 272 312 376
+ : J ~
abba cafe
? ? ? ?
125672 145376
-85 -70 -54 -2
abbacafe
0000004
无论您的区域设置如何,此方法都有效。
对于 mawk-1、mawk2-beta 和 nawk,您还可以从无符号字节值中减去 256 并使用printf("%c")
负数。 gawk 过去也允许这样做,但最近的版本可能已禁用它。