Несоответствия при упаковке шестнадцатеричной строки - PullRequest
0 голосов
/ 04 мая 2018

У меня возникают некоторые несоответствия при использовании hexdump и 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

Когда я запускаю ту же команду, кроме с hexdump -C:

echo -n "a42d9dfe8f93515d0d5f608a576044ce4c61e61e" \
  | sed 's/\(..\)/\1\n/g' \
  | awk '/^[a-fA-F0-9]{2}$/ { printf("%c",strtonum("0x" $0)); }' \
  | hexdump -C

Я получаю те же результаты (что касается символа "c2"):

00000000  c2 a4 2d c2 9d c3 be c2  8f c2 93 51 5d 0d 5f 60  |..-........Q]._`|
00000010  c2 8a 57 60 44 c3 8e 4c  61 c3 a6 1e              |..W`D..La...|

Однако, когда я запускаю hexdump без аргументов:

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, а не hexdump. Мысли?

Ответы [ 2 ]

0 голосов
/ 09 мая 2018

Почему бы не использовать 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..
0 голосов
/ 05 мая 2018

Проблема, которую вы наблюдаете, связана с кодировкой UTF-8 и little-endiannes.

Во-первых, обратите внимание, что когда вы пытаетесь напечатать любой символ Юникода в AWK, например 0xA4 (CURRENCY SIGN) , он фактически выдает два байта вывода, например, два байта 0xC2 0xA4, которые вы видите в своем выход:

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

Выход:

00000000  c2 a4                                             |..|
00000002

Это относится к любому символу больше 0x7F, и это связано с кодировкой UTF-8, которая, вероятно, установлена ​​в вашей локали. (Примечание: некоторые реализации AWK будут иметь другое поведение для приведенного выше кода.)

Во-вторых, когда вы используете hexdump без аргумента -C, он отображает каждую пару байтов в порядке замены из-за little-endianness вашей машины. Это связано с тем, что каждая пара байтов затем обрабатывается как одно 16-битное слово вместо обработки каждого байта отдельно, как это делается с помощью команд xxd и hexdump -C. Таким образом, вывод xxd, который вы получаете, на самом деле является правильным побайтным представлением ввода.

В-третьих, если вы хотите получить точную строку байтов, которая закодирована в шестнадцатеричной строке, которую вы передаете в sed, вы можете использовать это решение 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: a42d 9dfe 8f93 515d 0d5f 608a 5760 44ce  .-....Q]._`.W`D.
00000010: 4c61 e61e                                La..
...