Bash 填充十六进制字符串时不一致

Bash 填充十六进制字符串时不一致,bash,awk,sed,hexdump,xxd,Bash,Awk,Sed,Hexdump,Xxd,我在使用hextump和xxd时遇到了一些不一致的地方。当我运行以下命令时: echo -n "a42d9dfe8f93515d0d5f608a576044ce4c61e61e" \ | sed 's/\(..\)/\1\n/g' \ | awk '/^[a-fA-F0-9]{2}$/ { printf("%c",strtonum("0x" $0)); }' \ | xxd 它返回以下结果: 00000000: c2a4 2dc2 9dc3 bec2 8fc2 9351 5d0d

我在使用hextump和xxd时遇到了一些不一致的地方。当我运行以下命令时:

echo -n "a42d9dfe8f93515d0d5f608a576044ce4c61e61e" \
  | sed 's/\(..\)/\1\n/g' \
  | awk '/^[a-fA-F0-9]{2}$/ { printf("%c",strtonum("0x" $0)); }' \
  | xxd
它返回以下结果:

00000000: c2a4 2dc2 9dc3 bec2 8fc2 9351 5d0d 5f60  ..-........Q]._`
00000010: c28a 5760 44c3 8e4c 61c3 a61e            ..W`D..La...
请注意“c2”字符。我运行
xxd-p时也会发生这种情况

当我运行相同的命令时,除了hextump-C之外:

echo -n "a42d9dfe8f93515d0d5f608a576044ce4c61e61e" \
  | sed 's/\(..\)/\1\n/g' \
  | awk '/^[a-fA-F0-9]{2}$/ { printf("%c",strtonum("0x" $0)); }' \
  | hexdump -C
我得到了相同的结果(包括“c2”字符):

但是,当我在没有参数的情况下运行hextump时:

echo -n "a42d9dfe8f93515d0d5f608a576044ce4c61e61e" \
  | sed 's/\(..\)/\1\n/g' \
  | awk '/^[a-fA-F0-9]{2}$/ { printf("%c",strtonum("0x" $0)); }' \
  | hexdump
我得到以下[正确]结果:

0000000 a4c2 c22d c39d c2be c28f 5193 0d5d 605f
0000010 8ac2 6057 c344 4c8e c361 1ea6

在这个脚本中,我宁愿使用xxd而不是hextump。想法?

您观察到的问题是由于UTF-8编码和小端数

首先,请注意,当您尝试在AWK中打印任何Unicode字符时,它实际上会生成两个字节的输出,就像您在输出中看到的两个字节0xC2 0xA4一样:

$ echo 1 | awk 'BEGIN { printf("%c", 0xA4) }' | hexdump -C
输出:

00000000  c2 a4                                             |..|
00000002
00000000: a42d 9dfe 8f93 515d 0d5f 608a 5760 44ce  .-....Q]._`.W`D.
00000010: 4c61 e61e                                La..
这适用于任何大于0x7F的字符,这是由于UTF-8编码,这可能是在您的区域设置中设置的。(注意:对于上述代码,某些AWK实现将具有不同的行为。)

其次,当您在不带参数的情况下使用
hextump
时,由于您的机器的原因,它会以交换顺序显示每对字节。这是因为每对字节随后被视为一个16位字,而不是像
xxd
hextump-C
命令那样单独处理每个字节。因此,您得到的
xxd
输出实际上是输入的正确逐字节表示

第三,如果要生成以十六进制字符串编码的精确字节字符串,您可以使用以下Python解决方案:

echo -n "a42d9dfe8f93515d0d5f608a576044ce4c61e61e" | sed 's/\(..\)/0x\1,/g' | python3 -c "import sys;[open('tmp','wb').write(bytearray(eval('[' + line + ']'))) for line in sys.stdin]" && cat tmp | xxd
输出:

00000000  c2 a4                                             |..|
00000002
00000000: a42d 9dfe 8f93 515d 0d5f 608a 5760 44ce  .-....Q]._`.W`D.
00000010: 4c61 e61e                                La..

您观察到的问题是由于UTF-8编码和少量endiannes

首先,请注意,当您尝试在AWK中打印任何Unicode字符时,它实际上会生成两个字节的输出,就像您在输出中看到的两个字节0xC2 0xA4一样:

$ echo 1 | awk 'BEGIN { printf("%c", 0xA4) }' | hexdump -C
输出:

00000000  c2 a4                                             |..|
00000002
00000000: a42d 9dfe 8f93 515d 0d5f 608a 5760 44ce  .-....Q]._`.W`D.
00000010: 4c61 e61e                                La..
这适用于任何大于0x7F的字符,这是由于UTF-8编码,这可能是在您的区域设置中设置的。(注意:对于上述代码,某些AWK实现将具有不同的行为。)

其次,当您在不带参数的情况下使用
hextump
时,由于您的机器的原因,它会以交换顺序显示每对字节。这是因为每对字节随后被视为一个16位字,而不是像
xxd
hextump-C
命令那样单独处理每个字节。因此,您得到的
xxd
输出实际上是输入的正确逐字节表示

第三,如果要生成以十六进制字符串编码的精确字节字符串,您可以使用以下Python解决方案:

echo -n "a42d9dfe8f93515d0d5f608a576044ce4c61e61e" | sed 's/\(..\)/0x\1,/g' | python3 -c "import sys;[open('tmp','wb').write(bytearray(eval('[' + line + ']'))) for line in sys.stdin]" && cat tmp | xxd
输出:

00000000  c2 a4                                             |..|
00000002
00000000: a42d 9dfe 8f93 515d 0d5f 608a 5760 44ce  .-....Q]._`.W`D.
00000010: 4c61 e61e                                La..

为什么不将xxd与-r和-p一起使用呢

echo a42d9dfe8f93515d0d5f608a576044ce4c61e61e | xxd -r -p | xxd
输出

0000000: a42d 9dfe 8f93 515d 0d5f 608a 5760 44ce  .-....Q]._`.W`D.
0000010: 4c61 e61e                                La..

为什么不将xxd与-r和-p一起使用呢

echo a42d9dfe8f93515d0d5f608a576044ce4c61e61e | xxd -r -p | xxd
输出

0000000: a42d 9dfe 8f93 515d 0d5f 608a 5760 44ce  .-....Q]._`.W`D.
0000010: 4c61 e61e                                La..