converte file di testo di bit in file binario


12

Ho un file instructions.txtcon il contenuto:

00000000000000000000000000010011
00000010110100010010000010000011
00000000011100110000001010110011
00000000011100110000010000110011
00000000011100110110010010110011
00000000000000000000000000010011

Come posso creare un file binario con instructions.bingli stessi dati di instructions.txt. In altre parole, il .binfile dovrebbe essere gli stessi 192 bit presenti nel .txtfile, con 32 bit per riga. Sto usando bash su Ubuntu Linux. Stavo cercando di utilizzare xxd -b instructions.txtma l'output è molto più lungo di 192 bit.

Risposte:


6

oneliner per convertire stringhe a 32 bit di uno e zeri nel corrispondente binario:

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

cosa fa:

  • perl -neeseguirà l'iterazione attraverso ciascuna riga del file di input fornito su STDIN ( instructions.txt)
  • pack("B32", $_)prenderà un elenco di stringhe di 32 bit ( $_che abbiamo appena letto da STDIN) e lo convertirà in valore binario (in alternativa potresti usare "b32"se volessi un ordine di bit crescente all'interno di ogni byte invece di un ordine di bit decrescente; vedi perldoc -f packper maggiori dettagli)
  • print genererebbe quindi quel valore convertito in STDOUT, che reindirizzeremo quindi al nostro file binario instructions.bin

verificare:

$ 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

L'aggiunta -rdell'opzione (modalità inversa) in xxd -brealtà non funziona come previsto, perché xxd semplicemente non supporta la combinazione di questi due flag (ignora -bse vengono forniti entrambi). Invece, devi prima convertire i bit in hex. Ad esempio in questo modo:

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

Spiegazione completa:

  • La parte tra parentesi crea uno bcscript. Innanzitutto imposta la base di input su binario (2) e la base di output su esadecimale (16). Successivamente, il sedcomando stampa il contenuto di instructions.txtun punto e virgola tra ciascun gruppo di 4 bit, che corrisponde a 1 cifra esadecimale. Il risultato viene convogliato bc.
  • Il punto e virgola è un separatore di comandi in bcentrata, quindi tutto lo script fa stampare indietro ogni numero intero di input (dopo la conversione di base).
  • L'output di bcè una sequenza di cifre esadecimali, che può essere convertita in un file con il solito xxd -r -p.

Produzione:

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

Spiacente, c'è ancora un bug di endianness in questo. Lavorando per risolverlo!
nomadictype

1
In realtà, va bene. Sono stato confuso in precedenza utilizzando la larghezza di output errata nell'ultimo comando xxd.
nomadictype,

1
Ho provato la sceneggiatura e funziona, ma le uscite: (standard_in) 1: syntax error. Puoi spiegare a cosa syntax errorsi riferisce o perché ciò accade? Questo succede anche sulla tua macchina?
dopamane,

2

La mia risposta iniziale era corretta - xxdnon può accettare né -po -rcon -b...

Dato che le altre risposte sono realizzabili e nell'interesse di " un altro modo ", che ne dici di quanto segue:

Ingresso

$ cat instructions.txt
00000000000000000000000000010011
00000010110100010010000010000011
00000000011100110000001010110011
00000000011100110000010000110011
00000000011100110110010010110011
00000000000000000000000000010011

Produzione

$ 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

Pipeline di Bash:

cat instructions.txt \
    | tr -d $'\n' \
    | while read -N 4 nibble; do 
        printf '%x' "$((2#${nibble}))"; \
      done \
    | xxd -r -p \
    > instructions.bin
  • cat - inutile, ma usato per chiarezza
  • tr -d $'\n' - rimuove tutte le nuove righe dall'input
  • read -N 4 nibble- legge esattamente 4 × caratteri nella nibblevariabile
  • printf '%x' "$((2#${nibble}))" converte il bocconcino da binario a 1 × carattere esadecimale
    • $((2#...)) - converti il ​​valore dato dalla base 2 (binario) alla base 10 (decimale)
    • printf '%x' - formatta il valore dato dalla base 10 (decimale) alla base 16 (esadecimale)
  • xxd -r -p- reverse ( -r) un semplice dump ( -p) - da binario esadecimale a raw

Pitone:

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
  • Un heredoc ( << EOF) non quotato viene utilizzato per ottenere contenuti nel codice Python
    • Questo non è efficace se l'input diventa grande
  • cate tr- usato per ottenere un input pulito (una riga)
  • range(0, len(d), 8)- ottenere un elenco di numeri da 0 alla fine della stringa d, facendo un passo di 8 × caratteri alla volta.
  • chr(int(d[i:i+8],2))- converti l'attuale slice ( d[i:i+8]) da binario a decimale ( int(..., 2)), quindi in un carattere grezzo ( chr(...))
  • [ x for y in z]- comprensione della lista
  • ''.join(...) - converti l'elenco di caratteri in una singola stringa
  • print(...) - stampalo

1
Nota: in molte shell |alla fine di una riga funziona come una barra rovesciata: il comando continua alla riga successiva. In questo modo è possibile eliminare alcune barre rovesciate. Non sono sicuro che l'utilizzo di simboli di pipe dopo LF sia stata una decisione informata. Sto citando l'altro modo nel caso non lo sapessi.
Kamil Maciorowski,

1
Non lo sapevo, grazie! Mi piace spezzare la pipeline in linee logiche e avere i tubi |(o reindirizzamenti >, operatori booleani &&, ecc ...) esplicitamente in primo piano per visibilità / chiarezza ... forse una cosa stilistica / di preferenza.
Attie,

1
Dopo alcuni pensieri potrei iniziare a usare questo stile perché si può dire che le due linee sono collegate, esaminandone una qualsiasi . Se |è alla fine, la riga successiva potrebbe apparire come un comando autonomo, potrebbe essere fonte di confusione. Questo è il motivo per cui ho pensato che lo stile potesse essere la tua decisione informata.
Kamil Maciorowski,

Fantastico, fammi sapere come va :-)
Attie

1
Sta andando bene . :)
Kamil Maciorowski il

1

Puoi anche provare a postare questo sul sito CodeGolf SE, ma ecco la mia versione alternativa di Python (solo per kick challenge):

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

Supponendo che input.txtcontenga i tuoi dati, è formattato a 32 caratteri per riga.

Questo utilizza il structpacchetto Python 3 e la scrittura / lettura su stdin / out. (In Python 2 sarebbe stato più breve).

Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.