Konvertieren Sie eine Textdatei mit Bits in eine Binärdatei

12

Ich habe eine Datei instructions.txtmit dem Inhalt:

00000000000000000000000000010011
00000010110100010010000010000011
00000000011100110000001010110011
00000000011100110000010000110011
00000000011100110110010010110011
00000000000000000000000000010011

Wie kann ich eine binäre Datei erstellen , instructions.binwie die gleichen Daten instructions.txt. Mit anderen Worten, die .binDatei sollte die gleichen 192 Bits enthalten, die sich in der .txtDatei befinden, mit 32 Bits pro Zeile. Ich benutze Bash unter Ubuntu Linux. Ich habe versucht zu verwenden, xxd -b instructions.txtaber die Ausgabe ist viel länger als 192 Bit.

Dopaman
quelle

Antworten:

6

Oneliner zum Konvertieren von 32-Bit-Zeichenfolgen aus Einsen und Nullen in entsprechende Binärdateien:

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

Was es macht:

  • perl -nedurchläuft jede Zeile der auf STDIN ( instructions.txt) bereitgestellten Eingabedatei
  • pack("B32", $_)nimmt eine Zeichenfolgenliste mit 32 Bits ( $_die wir gerade aus STDIN gelesen haben) und konvertiert sie in einen Binärwert (Sie können sie auch verwenden, "b32"wenn Sie eine aufsteigende Bitreihenfolge innerhalb jedes Bytes anstelle einer absteigenden Bitreihenfolge wünschen; siehe perldoc -f packweitere Einzelheiten).
  • print würde dann diesen konvertierten Wert in STDOUT ausgeben, 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  ....
Matija Nalis
quelle
8

Das Hinzufügen der -rOption (umgekehrter Modus) zu xxd -bfunktioniert nicht wie beabsichtigt, da xxd das Kombinieren dieser beiden Flags einfach nicht unterstützt (es wird ignoriert, -bwenn beide angegeben sind). Stattdessen müssen Sie die Bits zuerst konvertieren, um sich selbst zu verhexen. Zum Beispiel so:

( echo 'obase=16;ibase=2'; sed -Ee 's/[01]{4}/;\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 von instructions.txtmit einem Semikolon zwischen jeder Gruppe von 4 Bits, was einer hexadezimalen Ziffer entspricht. Das Ergebnis wird weitergeleitet bc.
  • Das Semikolon ist ein Befehlstrennzeichen in bc. Das Skript druckt also nur jede Eingabe-Ganzzahl zurück (nach der Basiskonvertierung).
  • Die Ausgabe von bcist eine Folge von Hex-Ziffern, die mit den üblichen in eine Datei konvertiert 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  ....
Nomadentyp
quelle
Entschuldigung, es gibt immer noch einen Endianness-Fehler. Arbeiten Sie daran, es zu reparieren!
Nomadentyp
1
Eigentlich ist es in Ordnung. Ich war früher verwirrt, als ich im letzten xxd-Befehl die falsche Ausgabebreite verwendet habe.
Nomadentyp
1
Ich habe das Skript getestet und es funktioniert aber gibt aus : (standard_in) 1: syntax error. Können Sie erklären, worauf syntax errores sich bezieht oder warum dies geschieht? Passiert das auch auf Ihrer Maschine?
Dopamane
2

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

Angesichts der Tatsache, dass die anderen Antworten praktikabel sind und im Interesse eines " anderen Weges ", 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#${nibble}))"; \
      done \
    | xxd -r -p \
    > instructions.bin
  • cat - unnötig, aber aus Gründen der Klarheit verwendet
  • tr -d $'\n' - Entfernen Sie alle Zeilenumbrüche aus der Eingabe
  • read -N 4 nibble- Lesen Sie genau 4 × Zeichen in die nibbleVariable
  • printf '%x' "$((2#${nibble}))" Konvertieren Sie das Halbbyte von binär in 1 × Hex-Zeichen
    • $((2#...)) - Konvertieren Sie den angegebenen Wert von Basis 2 (binär) in Basis 10 (dezimal).
    • printf '%x' - Formatieren Sie den angegebenen Wert von Basis 10 (dezimal) bis Basis 16 (hexadezimal).
  • xxd -r -p- reverse ( -r) a plain 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 Inhalte in den Python-Code zu bringen
    • Dies ist nicht effizient, wenn der Eingang groß wird
  • catund tr- wird verwendet, um eine saubere (einzeilige) Eingabe zu erhalten
  • range(0, len(d), 8)- Holen Sie sich eine Liste mit Zahlen von 0 bis zum Ende der Zeichenfolge d, wobei Sie jeweils 8 × Zeichen eingeben.
  • chr(int(d[i:i+8],2))- Konvertieren Sie 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]- Listenverständnis
  • ''.join(...) - Konvertieren Sie die Liste der Zeichen in eine einzelne Zeichenfolge
  • print(...) - Druck es
Attie
quelle
1
Hinweis: In vielen Shells |am Ende einer Zeile funktioniert dies wie ein Backslash: Der Befehl fährt mit der nächsten Zeile fort. Auf diese Weise können Sie einige Backslashes entfernen. Ich bin mir nicht sicher, ob die Verwendung von Pipe-Symbolen nach LFs Ihre informierte Entscheidung war. Ich erwähne den anderen Weg, falls Sie es nicht wussten.
Kamil Maciorowski
1
Ich wusste es nicht, danke! Ich mag es, die Pipeline in logische Zeilen zu unterteilen und die Pipes |(oder Weiterleitungen >, boolesche Operatoren &&usw.) aus Gründen der Sichtbarkeit / Klarheit explizit im Vordergrund zu haben ... vielleicht eine stilistische / bevorzugte Sache.
Attie
1
Nach einigen Überlegungen kann ich anfangen, diesen Stil zu verwenden, da man erkennen kann, dass die beiden Linien verbunden sind, indem man eine von ihnen untersucht. Wenn |am Ende die nächste Zeile wie ein eigenständiger Befehl aussieht, kann dies verwirrend sein. Aus diesem Grund dachte ich, der Stil könnte Ihre informierte Entscheidung sein.
Kamil Maciorowski
Super, lass es mich wissen, wie es geht :-)
Attie
1
Es läuft gut . :)
Kamil Maciorowski
1

Sie können auch versuchen, dies auf der CodeGolf SE-Website 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, Sie input.txtenthalten Ihre Daten und sind mit 32 Zeichen pro Zeile formatiert.

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

wvxvw
quelle