Konvertieren Sie die Bitdatei in eine Binärdatei

1417
DavOS

Ich habe eine Datei instructions.txtmit dem Inhalt:

00000000000000000000000000010011 00000010110100010010000010000011 00000000011100110000001010110011 00000000011100110000010000110011 00000000011100110110010010110011 00000000000000000000000000010011 

Wie kann ich eine Binärdatei instructions.binmit den gleichen Daten erstellen wie instructions.txt. Mit anderen Worten, die .binDatei sollte die gleichen 192 Bits wie die .txtDatei haben, mit 32 Bits pro Zeile. Ich verwende bash unter Ubuntu Linux. Ich habe versucht zu verwenden, xxd -b instructions.txtaber die Ausgabe ist viel länger als 192 Bit.

10

4 Antworten auf die Frage

8
nomadictype

Das Hinzufügen der -rOption (Reverse-Modus) zu to xxd -bfunktioniert nicht wirklich wie beabsichtigt, da xxd die Kombination dieser beiden Flags einfach nicht unterstützt (es wird ignoriert, -bwenn beide angegeben werden). Stattdessen müssen Sie die Bits zuerst selbst in Hex konvertieren. Zum Beispiel so:

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

Vollständige Erklärung:

  • Der Teil in den Klammern erstellt ein bcSkript. Zunächst wird die Eingangsbasis auf Binär (2) und die Ausgangsbasis auf Hexadezimal (16) gesetzt. Danach seddruckt der Befehl den Inhalt instructions.txtmit einem Semikolon zwischen jeder Gruppe von 4 Bits, was einer Hexadezimalstelle entspricht. Das Ergebnis wird weitergeleitet bc.
  • Das Semikolon ist ein Befehlstrennzeichen, dh bc, das gesamte Skript besteht darin, jede eingegebene Ganzzahl (nach der Basiskonvertierung) erneut auszugeben.
  • Die Ausgabe von bcist eine Folge von Hex-Ziffern, die mit den üblichen in eine Datei umgewandelt werden können xxd -r -p.

Ausgabe:

$ 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 .... 
Entschuldigung, hier ist noch ein Endianness-Fehler. An der Reparatur arbeiten! nomadictype vor 6 Jahren 0
Eigentlich ist es gut. Ich war früher verwirrt durch die Verwendung der falschen Ausgabebreite im letzten xxd-Befehl. nomadictype vor 6 Jahren 1
Ich habe das Skript getestet und es funktioniert, gibt aber aus: `(standard_in) 1: Syntaxfehler`. Können Sie erklären, auf welchen "Syntaxfehler" es sich bezieht oder warum dies auftritt? Kommt das auch auf Ihrer Maschine vor? DavOS vor 6 Jahren 1
5
Matija Nalis

oneliner, um 32-Bit-Folgen von Einsen und Nullen in entsprechende Binärzeichen umzuwandeln:

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

Was es macht:

  • perl -nedurchläuft jede Zeile der Eingabedatei von STDIN ( instructions.txt)
  • pack("B32", $_)nimmt eine String-Liste mit 32 Bits ( $_die wir gerade aus STDIN gelesen haben) und konvertiert sie in einen Binärwert (Sie können alternativ verwenden, "b32"wenn Sie in jedem Byte eine aufsteigende Bit-Reihenfolge anstelle der absteigenden Bit-Reihenfolge wünschen ; perldoc -f packweitere Einzelheiten hierzu)
  • print Dieser konvertierte Wert würde dann in STDOUT ausgegeben, den wir dann in unsere Binärdatei umleiten instructions.bin

überprüfen:

$ 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

Meine ursprüngliche Antwort war falsch - xxdkann weder akzeptieren -pnoch -rmit -b...

In Anbetracht der Tatsache, dass die anderen Antworten praktikabel sind, und im Interesse einer " anderen Art ", wie wäre es mit Folgendem:

Eingang

$ cat instructions.txt 00000000000000000000000000010011 00000010110100010010000010000011 00000000011100110000001010110011 00000000011100110000010000110011 00000000011100110110010010110011 00000000000000000000000000010011 

Ausgabe

$ 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-Pipeline:

cat instructions.txt \ | tr -d $'\n' \ | while read -N 4 nibble; do  printf '%x' "$((2#$))"; \ done \ | xxd -r -p \ > instructions.bin 
  • cat - unnötig, wird aber aus Gründen der Übersichtlichkeit verwendet
  • tr -d $'\n' - alle Zeilenumbrüche aus der Eingabe entfernen
  • read -N 4 nibble- Lesen Sie exakt 4 × Zeichen in die nibbleVariable
  • printf '%x' "$((2#$))" wandeln Sie das Nibble von binär in 1 × Hex-Zeichen um
    • $((2#...)) - konvertiere den angegebenen Wert von Basis 2 (binär) in Basis 10 (dezimal)
    • printf '%x' - formatiere den angegebenen Wert von Basis 10 (dezimal) bis Basis 16 (hexadezimal)
  • xxd -r -p- reverse ( -r) ein einfacher Dump ( -p) - von Hexadezimal zu Roh-Binär

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 
  • Ein nicht zitiertes heredoc ( << EOF) wird verwendet, um Inhalt in den Python-Code zu übernehmen
    • Dies ist nicht effizient, wenn die Eingabe groß wird
  • catund tr- wird verwendet, um eine saubere (einzeilige) Eingabe zu erhalten
  • range(0, len(d), 8)- eine Liste mit Zahlen von 0 bis zum Ende der Zeichenfolge dabrufen und dabei jeweils 8 × Zeichen eingeben.
  • chr(int(d[i:i+8],2))- Konvertiere das aktuelle Slice ( d[i:i+8]) von Binär in Dezimal ( int(..., 2)) und dann in ein Rohzeichen ( chr(...)).
  • [ x for y in z]- Verstehen auflisten
  • ''.join(...) - Konvertieren Sie die Liste der Zeichen in eine einzige Zeichenfolge
  • print(...) - Druck es
Hinweis: In vielen Shells wirkt `|` am Ende einer Zeile wie ein umgekehrter Schrägstrich: Der Befehl fährt mit der nächsten Zeile fort. Auf diese Weise können Sie einige Backslashes loswerden. Ich bin nicht sicher, ob die Verwendung von Pipe-Symbolen nach LFs Ihre fundierte Entscheidung war. Ich erwähne den anderen Weg, falls Sie es nicht wussten. Kamil Maciorowski vor 6 Jahren 1
Ich wusste es nicht, danke! Ich mag es, die Pipeline in logische Linien zu zerlegen und die Pipes `|` (oder die Weiterleitungen `>`, boolesche Operatoren `&&` usw.) explizit an der Front zu haben, um die Sichtbarkeit / Klarheit zu verbessern ... vielleicht eine Stilistik / Präferenzsache. Attie vor 6 Jahren 1
Nach einigen Überlegungen kann ich anfangen, diesen Stil zu verwenden, weil man feststellen kann, dass die beiden Linien miteinander verbunden sind, indem man * alle * von ihnen untersucht. Wenn sich `|` am Ende befindet, kann die nächste Zeile wie ein eigenständiger Befehl aussehen. Dies kann verwirrend sein. Deshalb dachte ich, der Stil könnte Ihre informierte Entscheidung sein. Kamil Maciorowski vor 6 Jahren 1
Toll, lass mich wissen wie es geht :-) Attie vor 6 Jahren 0
Es geht [gut] (https://superuser.com/a/1367255/432690). :) Kamil Maciorowski vor 6 Jahren 1
1
wvxvw

Sie können auch versuchen, dies auf der CodeGolf SE-Site zu veröffentlichen, aber hier ist meine alternative Python-Version (nur für 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 

Angenommen, input.txtenthält Ihre Daten und ist mit 32 Zeichen pro Zeile formatiert.

Dies verwendet Python 3- structPaket und Schreiben / Lesen zu stdin / out. (In Python 2 wäre es kürzer gewesen).