10

У меня есть файл instructions.txt с содержанием:

00000000000000000000000000010011
00000010110100010010000010000011
00000000011100110000001010110011
00000000011100110000010000110011
00000000011100110110010010110011
00000000000000000000000000010011

Как я могу создать двоичный файл instructions.bin из тех же данных, что и instructions.txt . Другими словами, файл .bin должен быть теми же 192 битами, что и файл .txt , с 32 битами на строку. Я использую Bash на Ubuntu Linux. Я пытался использовать xxd -b instructions.txt но вывод длиннее, чем 192 бит.

4 ответа4

8

Добавление опции -r (обратный режим) в xxd -b самом деле не работает должным образом, потому что xxd просто не поддерживает объединение этих двух флагов (он игнорирует -b если заданы оба). Вместо этого вы должны сначала преобразовать биты в гекс. Например, вот так:

( echo 'obase=16;ibase=2'; sed -Ee 's/[01]{4}/;\0/g' instructions.txt ) | bc | xxd -r -p > instructions.bin

Полное объяснение:

  • Часть внутри скобок создает скрипт bc . Сначала он устанавливает входную базу в двоичное (2), а выходную базу - в шестнадцатеричное (16). После этого команда sed распечатывает содержимое файла instructions.txt с точкой с запятой между каждой группой из 4 битов, что соответствует 1 шестнадцатеричной цифре. Результат поступает в bc
  • Точка с запятой - это разделитель команд в bc , поэтому все, что делает скрипт, это выводит каждое входное целое число обратно (после преобразования базы).
  • Вывод bc представляет собой последовательность шестнадцатеричных цифр, которую можно преобразовать в файл с обычным xxd -r -p .

Выход:

$ hexdump -Cv instructions.bin
00000000  00 00 00 13 02 d1 20 83  00 73 02 b3 00 73 04 33  |...... ..s...s.3|
00000010  00 73 64 b3 00 00 00 13                           |.sd.....|
00000018
$ xxd -b -c4 instructions.bin
00000000: 00000000 00000000 00000000 00010011  ....
00000004: 00000010 11010001 00100000 10000011  .. .
00000008: 00000000 01110011 00000010 10110011  .s..
0000000c: 00000000 01110011 00000100 00110011  .s.3
00000010: 00000000 01110011 01100100 10110011  .sd.
00000014: 00000000 00000000 00000000 00010011  ....
5

oneliner для преобразования 32-битных строк из единиц и нулей в соответствующий двоичный файл:

$ perl -ne 'print pack("B32", $_)' < instructions.txt > instructions.bin

что оно делает:

  • perl -ne будет перебирать каждую строку входного файла, предоставленного в STDIN (instructions.txt)
  • pack("B32", $_) возьмет список строк из 32 битов ($_ который мы только что прочитали из STDIN), и преобразует его в двоичное значение (вы можете альтернативно использовать "b32" если вы хотите, чтобы в каждом байт вместо порядка убывания битов; более подробную информацию смотрите в perldoc -f pack)
  • Затем print выведет это преобразованное значение в STDOUT, который мы затем перенаправим в наш двоичный файл instructions.bin

проверить:

$ hexdump -Cv instructions.bin
00000000  00 00 00 13 02 d1 20 83  00 73 02 b3 00 73 04 33  |...... ..s...s.3|
00000010  00 73 64 b3 00 00 00 13                           |.sd.....|
00000018

$ xxd -b -c4 instructions.bin
00000000: 00000000 00000000 00000000 00010011  ....
00000004: 00000010 11010001 00100000 10000011  .. .
00000008: 00000000 01110011 00000010 10110011  .s..
0000000c: 00000000 01110011 00000100 00110011  .s.3
00000010: 00000000 01110011 01100100 10110011  .sd.
00000014: 00000000 00000000 00000000 00010011  ....
2

Мой первоначальный ответ был неверным - xxd не может принять -p или -r с -b ...

Учитывая, что другие ответы работоспособны, и в интересах « другого пути », как насчет следующего:

вход

$ cat instructions.txt
00000000000000000000000000010011
00000010110100010010000010000011
00000000011100110000001010110011
00000000011100110000010000110011
00000000011100110110010010110011
00000000000000000000000000010011

Выход

$ hexdump -Cv < instructions.bin
00000000  00 00 00 13 02 d1 20 83  00 73 02 b3 00 73 04 33  |...... ..s...s.3|
00000010  00 73 64 b3 00 00 00 13                           |.sd.....|
00000018

Газопровод Bash:

cat instructions.txt \
    | tr -d $'\n' \
    | while read -N 4 nibble; do 
        printf '%x' "$((2#${nibble}))"; \
      done \
    | xxd -r -p \
    > instructions.bin
  • cat - ненужная, но используемая для наглядности
  • tr -d $'\n' - удалить все новые строки из ввода
  • read -N 4 nibble - прочитать ровно 4 × символа в переменную nibble
  • printf '%x' "$((2#${nibble}))" преобразует полубайт из двоичного в 1 × шестнадцатеричный символ
    • $((2#...)) - преобразовать данное значение из базы 2 (двоичная) в базу 10 (десятичная)
    • printf '%x' - отформатировать заданное значение от основания 10 (десятичное) до основания 16 (шестнадцатеричное)
  • xxd -r -p - обратный (-r) простой дамп (-p) - из шестнадцатеричного в необработанный двоичный файл

Python:

python << EOF > instructions.bin
d = '$(cat instructions.txt | tr -d $'\n')'
print(''.join([chr(int(d[i:i+8],2)) for i in range(0, len(d), 8)]))
EOF
  • Heredoc без кавычек (<< EOF) используется для получения содержимого в коде Python
    • Это не эффективно, если ввод становится большим
  • cat и tr - используются для получения чистого (однострочного) ввода
  • range(0, len(d), 8) - получить список чисел от 0 до конца строки d , шагая по 8 × символов за раз.
  • chr(int(d[i:i+8],2)) - преобразовать текущий фрагмент (d[i:i+8]) из двоичного в десятичное (int(..., 2)), а затем в необработанный символ (chr(...))
  • [ x for y in z] - понимание списка
  • ''.join(...) - преобразовать список символов в одну строку
  • print(...) - печатать
1

Вы также можете попробовать опубликовать это на сайте CodeGolf SE, но вот моя альтернативная версия Python (только для кик-апа):

python -c "import sys,struct;[sys.stdout.buffer.write(struct.pack('!i',int(x,2)))for x in sys.stdin]" \
< input.txt > output.bin

Предполагая, что input.txt содержит ваши данные, и он отформатирован до 32 символов в строке.

Это использует Python 3 struct package и запись / чтение в stdin / out. (В Python 2 это было бы короче).

Всё ещё ищете ответ? Посмотрите другие вопросы с метками .