Awk

為什麼 awk 的 printf 將大於 127 的字元值解釋為多字節字元?

  • January 25, 2022

ASCII 字元範圍是從 0 到 127,在該範圍內,帶有 %c 格式說明符的 awk 的 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?

這是UTF-8編碼。11000010 開始一個兩字節序列(前兩位置位後跟一個清零位),有效位為 00010000000(第一個字節的後五位,第二個字節的後六位),即 128 .

AWK 正在輸出此內容,因為您的語言環境設置為使用 UTF-8;您可以切換到非 UTF-8 語言環境以查看差異:

$ LC_ALL=C awk 'BEGIN{printf "%c", 128}' | xxd -b
00000000: 10000000

讓 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 過去也允許這樣做,但最近的版本可能已禁用它。

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