convertir archivos de texto de bits a archivos binarios


12

Tengo un archivo instructions.txtcon el contenido:

00000000000000000000000000010011
00000010110100010010000010000011
00000000011100110000001010110011
00000000011100110000010000110011
00000000011100110110010010110011
00000000000000000000000000010011

¿Cómo puedo crear un archivo binario con instructions.binlos mismos datos que instructions.txt? En otras palabras, el .binarchivo debe tener los mismos 192 bits que hay en el .txtarchivo, con 32 bits por línea. Estoy usando bash en Ubuntu Linux. Estaba tratando de usar, xxd -b instructions.txtpero la salida es mucho más larga que 192 bits.

Respuestas:


6

oneliner para convertir cadenas de unos y ceros de 32 bits en binarios correspondientes:

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

Que hace:

  • perl -neiterará a través de cada línea de archivo de entrada proporcionada en STDIN ( instructions.txt)
  • pack("B32", $_)tomará una lista de cadenas de 32 bits ( $_que acabamos de leer de STDIN) y la convertirá en valor binario (alternativamente, podría usarla "b32"si quisiera un orden de bits ascendente dentro de cada byte en lugar de un orden de bits descendente; consulte perldoc -f packpara obtener más detalles)
  • print luego generaría ese valor convertido a STDOUT, que luego redirigimos a nuestro archivo binario instructions.bin

verificar:

$ 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  ....

8

Agregar la -ropción (modo inverso) en xxd -brealidad no funciona según lo previsto, porque xxd simplemente no admite la combinación de estos dos indicadores (ignora -bsi se dan ambos). En su lugar, primero debes convertir los bits en hexadecimal. Por ejemplo así:

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

Explicación completa:

  • La parte dentro de los paréntesis crea un bcscript. Primero establece la base de entrada en binario (2) y la base de salida en hexadecimal (16). Después de eso, el sedcomando imprime el contenido de instructions.txtcon un punto y coma entre cada grupo de 4 bits, que corresponde a 1 dígito hexadecimal. El resultado se canaliza a bc.
  • El punto y coma es un separador de comando bc, por lo que todo lo que hace el script es volver a imprimir cada entero de entrada (después de la conversión base).
  • La salida de bces una secuencia de dígitos hexadecimales, que se pueden convertir a un archivo con el habitual xxd -r -p.

Salida:

$ 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  ....

Lo sentimos, todavía hay un error de endianness en esto. Trabajando en arreglarlo!
nomadictype

1
En realidad está bien. Estaba confundido anteriormente al usar el ancho de salida incorrecto en el último comando xxd.
nomadictype

1
He probado el guión y que funciona, pero salidas: (standard_in) 1: syntax error. ¿Puede explicar a qué syntax errorse refiere o por qué ocurre esto? ¿Esto también sucede en tu máquina?
dopamane

2

Mi respuesta original era incorrecto - xxdno puede aceptar cualquiera -po -rcon -b...

Dado que las otras respuestas son viables, y en interés de " otra forma ", ¿qué tal lo siguiente:

Entrada

$ cat instructions.txt
00000000000000000000000000010011
00000010110100010010000010000011
00000000011100110000001010110011
00000000011100110000010000110011
00000000011100110110010010110011
00000000000000000000000000010011

Salida

$ 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

Tubería Bash:

cat instructions.txt \
    | tr -d $'\n' \
    | while read -N 4 nibble; do 
        printf '%x' "$((2#${nibble}))"; \
      done \
    | xxd -r -p \
    > instructions.bin
  • cat - innecesario, pero usado para mayor claridad
  • tr -d $'\n' - eliminar todas las nuevas líneas de la entrada
  • read -N 4 nibble- lee exactamente 4 × caracteres en la nibblevariable
  • printf '%x' "$((2#${nibble}))" convierte el mordisco de binario a 1 × carácter hexadecimal
    • $((2#...)) - convierte el valor dado de base 2 (binario) a base 10 (decimal)
    • printf '%x' - formatee el valor dado de base 10 (decimal) a base 16 (hexadecimal)
  • xxd -r -p- reverse ( -r) un volcado simple ( -p) - de hexadecimal a binario sin formato

Pitón:

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
  • Se utiliza un heredoc ( << EOF) sin comillas para obtener contenido en el código de Python
    • Esto no es eficiente si la entrada se hace grande
  • caty tr- se utiliza para obtener una entrada limpia (una línea)
  • range(0, len(d), 8)- Obtenga una lista de números desde 0 hasta el final de la cadena d, paso a paso 8 × caracteres a la vez.
  • chr(int(d[i:i+8],2))- convierte el segmento actual ( d[i:i+8]) de binario a decimal ( int(..., 2)), y luego a un carácter sin formato ( chr(...))
  • [ x for y in z]- lista de comprensión
  • ''.join(...) - convierte la lista de caracteres en una sola cadena
  • print(...) - Imprímelo

1
Nota: en muchos shells |al final de una línea funciona como una barra invertida: el comando continúa a la siguiente línea. De esta manera, puede deshacerse de algunas barras invertidas. No estoy seguro si el uso de símbolos de tubería después de LF fue su decisión informada. Menciono lo contrario en caso de que no lo supieras.
Kamil Maciorowski

1
No lo sabia, gracias! Me gusta dividir la tubería en líneas lógicas, y tener las tuberías |(o redirecciones >, operadores booleanos &&, etc.) explícitamente en el frente para visibilidad / claridad ... tal vez una cuestión de estilo / preferencia.
Attie

1
Después de algunas reflexiones, puedo comenzar a usar este estilo porque uno puede decir que las dos líneas están conectadas, examinando cualquiera de ellas. Si |está al final, la siguiente línea puede parecer un comando independiente, puede ser confuso. Es por eso que pensé que el estilo podría ser tu decisión informada.
Kamil Maciorowski

Impresionante, que me haga saber cómo va :-)
Attie

1
Se va así . :)
Kamil Maciorowski

1

También puede intentar publicar esto en el sitio de CodeGolf SE, pero aquí está mi versión alternativa de Python (solo para desafío de patada):

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

Suponiendo que input.txtcontiene sus datos, y está formateado a 32 caracteres por línea.

Esto usa el structpaquete Python 3 y la escritura / lectura para stdin / out. (En Python 2 hubiera sido más corto).

Al usar nuestro sitio, usted reconoce que ha leído y comprende nuestra Política de Cookies y Política de Privacidad.
Licensed under cc by-sa 3.0 with attribution required.