преобразовать текстовый файл битов в двоичный файл

1294
DavOS

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

00000000000000000000000000010011 00000010110100010010000010000011 00000000011100110000001010110011 00000000011100110000010000110011 00000000011100110110010010110011 00000000000000000000000000010011 

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

10

4 ответа на вопрос

8
nomadictype

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

( echo 'obase=16;ibase=2'; sed -Ee 's/[01]/;\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 .... 
Извините, в этом все еще есть ошибка порядка байтов. Работаем над его исправлением! nomadictype 5 лет назад 0
Actually, it's fine. I was confused earlier by using the wrong output width in the last xxd command. nomadictype 5 лет назад 1
I've tested the script and it works but outputs: `(standard_in) 1: syntax error`. Can you explain what `syntax error` it is referring to or why this occurs? Does this happen on your machine too? DavOS 5 лет назад 1
5
Matija Nalis

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
Attie

Мой первоначальный ответ был неверным - 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#$))"; \ done \ | xxd -r -p \ > instructions.bin 
  • cat - не нужно, но используется для ясности
  • tr -d $'\n' - удалить все новые строки из ввода
  • read -N 4 nibble- прочитать ровно 4 × символа в nibbleпеременную
  • printf '%x' "$((2#$))" преобразовать клочок из двоичного в 1 × шестнадцатеричный символ
    • $((2#...)) - преобразовать данное значение из базы 2 (двоичная) в базу 10 (десятичная)
    • printf '%x' - отформатировать данное значение от основания 10 (десятичное) до основания 16 (шестнадцатеричное)
  • xxd -r -p- reverse ( -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))- преобразовать текущий slice ( d[i:i+8]) из двоичного в десятичное ( int(..., 2)), а затем в необработанный символ ( chr(...))
  • [ x for y in z]- понимание списка
  • ''.join(...) - преобразовать список символов в одну строку
  • print(...) - распечатай
Примечание: во многих оболочках `|` в конце строки работает как обратный слеш: команда переходит к следующей строке. Таким образом, вы можете избавиться от нескольких обратных наклонных черт. Я не уверен, что использование символов канала после LF было вашим осознанным решением. Я упоминаю другой способ, если ты не знал. Kamil Maciorowski 5 лет назад 1
I didn't know, thanks! I do like breaking the pipeline into logical lines, and having the pipes `|` (or redirects `>`, boolean operators `&&`, etc...) explicitly at the front for visibility / clarity... perhaps a stylistic / preference thing. Attie 5 лет назад 1
After some thoughts I may start using this style because one can tell the two lines are connected, by examining *any* of them. If `|` is at the end, the next line may look like a standalone command, it may be confusing. This is why I thought the style might be your informed decision. Kamil Maciorowski 5 лет назад 1
Awesome, let me know how it goes :-) Attie 5 лет назад 0
Это идет [хорошо] (https://superuser.com/a/1367255/432690). :) Kamil Maciorowski 5 лет назад 1
1
wvxvw

Вы также можете попробовать опубликовать это на сайте 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 символов в строке.

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

Похожие вопросы