convertir un fichier texte de bits en fichier binaire


12

J'ai un fichier instructions.txtavec le contenu:

00000000000000000000000000010011
00000010110100010010000010000011
00000000011100110000001010110011
00000000011100110000010000110011
00000000011100110110010010110011
00000000000000000000000000010011

Comment puis-je créer un fichier binaire instructions.bindes mêmes données que instructions.txt. En d'autres termes, le .binfichier doit être le même 192 bits qui sont dans le .txtfichier, avec 32 bits par ligne. J'utilise bash sur Ubuntu Linux. J'essayais d'utiliser xxd -b instructions.txtmais la sortie est bien plus longue que 192 bits.

Réponses:


6

oneliner pour convertir des chaînes de 32 bits de uns et de zéros en binaire correspondant:

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

ce qu'il fait:

  • perl -neva parcourir chaque ligne du fichier d'entrée fourni sur STDIN ( instructions.txt)
  • pack("B32", $_)prendra une liste de chaînes de 32 bits ( $_que nous venons de lire à partir de STDIN) et la convertira en valeur binaire (vous pouvez également utiliser "b32"si vous souhaitez un ordre de bits croissant dans chaque octet au lieu d'un ordre de bits décroissant; voir perldoc -f packpour plus de détails)
  • print sortirait ensuite cette valeur convertie en STDOUT, que nous redirigeons ensuite vers notre fichier binaire instructions.bin

Vérifier:

$ 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'ajout de l' -roption (mode inverse) à xxd -bne fonctionne pas comme prévu, car xxd ne prend tout simplement pas en charge la combinaison de ces deux indicateurs (il ignore -bsi les deux sont donnés). Au lieu de cela, vous devez d'abord convertir les bits en hexadécimal. Par exemple, comme ceci:

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

Explication complète:

  • La partie entre parenthèses crée un bcscript. Il définit d'abord la base d'entrée sur binaire (2) et la base de sortie sur hexadécimal (16). Après cela, la sedcommande imprime le contenu de instructions.txtavec un point-virgule entre chaque groupe de 4 bits, ce qui correspond à 1 chiffre hexadécimal. Le résultat est canalisé dansbc .
  • Le point-virgule est un séparateur de commandes dans bc , donc tout ce que fait le script est de faire ressortir chaque entier d'entrée (après conversion de base).
  • La sortie de bcest une séquence de chiffres hexadécimaux, qui peut être convertie en un fichier avec l'habituel xxd -r -p.

Production:

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

Désolé, il y a toujours un bogue d'endianness. Travailler à le réparer!
nomadictype

1
En fait, ça va. J'étais confus plus tôt en utilisant la mauvaise largeur de sortie dans la dernière commande xxd.
nomadictype

1
Je l' ai testé le script et il fonctionne , mais les sorties: (standard_in) 1: syntax error. Pouvez-vous expliquer de quoi syntax erroril s'agit ou pourquoi cela se produit? Cela se produit-il également sur votre machine?
dopamane du

2

Ma réponse d'origine était incorrecte - xxdne peut accepter ni l'un -pni l' autre -ravec -b...

Étant donné que les autres réponses sont réalisables et dans l’intérêt d’ une « autre manière ", que diriez-vous des éléments suivants:

Contribution

$ cat instructions.txt
00000000000000000000000000010011
00000010110100010010000010000011
00000000011100110000001010110011
00000000011100110000010000110011
00000000011100110110010010110011
00000000000000000000000000010011

Production

$ 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 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, mais utilisé pour plus de clarté
  • tr -d $'\n' - supprimer toutes les nouvelles lignes de l'entrée
  • read -N 4 nibble- lire exactement 4 × caractères dans la nibblevariable
  • printf '%x' "$((2#${nibble}))" convertir le quartet de binaire en 1 × caractère hexadécimal
    • $((2#...)) - convertir la valeur donnée de la base 2 (binaire) en base 10 (décimal)
    • printf '%x' - formate la valeur donnée de la base 10 (décimale) à la base 16 (hexadécimale)
  • xxd -r -p- reverse ( -r) un vidage simple ( -p) - de l'hexadécimal au binaire brut

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
  • Un hérédoc non cité (<< EOF ) est utilisé pour obtenir du contenu dans le code Python
    • Ce n'est pas efficace si l'entrée devient grande
  • catet tr- utilisé pour obtenir une entrée propre (une ligne)
  • range(0, len(d), 8)- obtenir une liste de nombres de 0 à la fin de la chaîne d, en progressant de 8 × caractères à la fois.
  • chr(int(d[i:i+8],2))- convertir la tranche actuelle ( d[i:i+8]) de binaire en decimal ( int(..., 2)), puis en caractère brut ( chr(...))
  • [ x for y in z]- compréhension de la liste
  • ''.join(...) - convertir la liste des caractères en une seule chaîne
  • print(...) - imprime le

1
Remarque: dans de nombreux shells |à la fin d'une ligne fonctionne comme une barre oblique inverse: la commande continue à la ligne suivante. De cette façon, vous pouvez vous débarrasser de quelques barres obliques inverses. Je ne sais pas si l'utilisation de symboles de tuyau après les LF a été votre décision éclairée. Je mentionne l'autre sens au cas où vous ne le sauriez pas.
Kamil Maciorowski

1
Je ne savais pas, merci! J'aime casser le pipeline en lignes logiques, et avoir les tuyaux |(ou redirections >, opérateurs booléens &&, etc ...) explicitement à l'avant pour la visibilité / clarté ... peut-être une chose stylistique / de préférence.
Attie

1
Après quelques réflexions, je peux commencer à utiliser ce style car on peut dire que les deux lignes sont connectées, en examinant l' une d'entre elles. Si |est à la fin, la ligne suivante peut ressembler à une commande autonome, cela peut prêter à confusion. C'est pourquoi j'ai pensé que le style pourrait être votre décision éclairée.
Kamil Maciorowski

Génial, laissez-moi savoir comment ça se passe :-)
Attie

1
Ça va bien . :)
Kamil Maciorowski

1

Vous pouvez aussi essayer de poster ceci sur le site CodeGolf SE, mais voici ma version alternative de Python (juste pour le défi de coup de pied):

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

En supposant input.txt contient vos données et qu'elles sont formatées à 32 caractères par ligne.

Cela utilise le structpackage Python 3 et l'écriture / lecture dans stdin / out. (En Python 2, il aurait été plus court).

En utilisant notre site, vous reconnaissez avoir lu et compris notre politique liée aux cookies et notre politique de confidentialité.
Licensed under cc by-sa 3.0 with attribution required.