it-swarm.com.de

konvertiert eine Textdatei von Bits in eine Binärdatei

Ich habe eine Datei instructions.txt mit dem Inhalt:

00000000000000000000000000010011
00000010110100010010000010000011
00000000011100110000001010110011
00000000011100110000010000110011
00000000011100110110010010110011
00000000000000000000000000010011

Wie kann ich eine Binärdatei instructions.bin mit den gleichen Daten wie instructions.txt erstellen? Mit anderen Worten, die .bin-Datei sollte die gleichen 192 Bit wie die .txt-Datei enthalten, mit 32 Bit pro Zeile. Ich benutze Bash unter Ubuntu Linux. Ich habe versucht, xxd -b instructions.txt zu verwenden, aber die Ausgabe ist viel länger als 192 Bit.

10
dopamane

oneliner zum Konvertieren von 32-Bit-Folgen von Einsen und Nullen in entsprechende Binärdateien:

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

was es macht:

  • Perl -ne durchläuft jede auf STDIN bereitgestellte Zeile der Eingabedatei (instructions.txt)
  • pack("B32", $_) nimmt eine String-Liste mit 32 Bits ($_, den wir gerade aus STDIN gelesen haben) und konvertiert sie in einen Binärwert (Sie können alternativ "b32" verwenden, wenn Sie eine aufsteigende Bitreihenfolge innerhalb jedes Bytes anstelle einer absteigenden Bitreihenfolge wünschen; weitere Informationen finden Sie unter perldoc -f pack Einzelheiten)
  • print würde dann diesen konvertierten Wert an STDOUT ausgeben, den wir dann in unsere Binärdatei instructions.bin umleiten.

ü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  ....
5
Matija Nalis

Das Hinzufügen der Option -r (umgekehrter Modus) zu xxd -b funktioniert nicht wie beabsichtigt, da xxd die Kombination dieser beiden Flags einfach nicht unterstützt (-b wird ignoriert, wenn beide angegeben sind). Stattdessen müssen Sie zuerst die Bits in Hex konvertieren. 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 Klammern erstellt ein bc-Skript. Zuerst wird die Eingabebasis auf binär (2) und die Ausgabebasis auf hexadezimal (16) gesetzt. Danach gibt der Befehl sed den Inhalt von instructions.txt mit einem Semikolon zwischen jeder Gruppe von 4 Bits aus, was einer Hexadezimalzahl entspricht. Das Ergebnis wird in bc weitergeleitet.
  • Das Semikolon ist ein Befehlstrennzeichen in bc, daher gibt das Skript nur jede eingegebene Ganzzahl aus (nach der Basiskonvertierung).
  • Die Ausgabe von bc ist eine Folge von Hex-Ziffern, die mit dem üblichen xxd -r -p in eine Datei konvertiert werden kann.

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  ....
8
nomadictype

Meine ursprüngliche Antwort war falsch - xxd kann weder -p noch -r mit -b akzeptieren ...

Angesichts der Tatsache, dass die anderen Antworten praktikabel sind und im Interesse von " anders ", wie sieht es mit Folgendem aus:

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 - nicht erforderlich, wird jedoch aus Gründen der Übersichtlichkeit verwendet
  • tr -d $'\n' - Alle Zeilenumbrüche aus der Eingabe entfernen
  • read -N 4 nibble - liest genau 4 × Zeichen in die Variable nibble ein
  • printf '%x' "$((2#${nibble}))" konvertiert das Halbbyte von binär auf 1 × hexadezimal
    • $((2#...)) - konvertiert den angegebenen Wert von der Basis 2 (binär) zur Basis 10 (dezimal)
    • printf '%x' - formatiere den angegebenen Wert von Basis 10 (dezimal) bis Basis 16 (hexadezimal)
  • xxd -r -p - Kehrt (-r) einen einfachen Speicherauszug (-p) um - von hexadezimal zu roher Binärdatei

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 zitierter Heredoc (<< EOF) wird verwendet, um Inhalt in den Python-Code zu bekommen
    • Dies ist nicht effizient, wenn die Eingabe groß wird
  • cat und tr - werden verwendet, um eine saubere (einzeilige) Eingabe zu erhalten
  • range(0, len(d), 8) - Ermittelt eine Liste mit Zahlen von 0 bis zum Ende der Zeichenfolge d mit jeweils 8 Zeichen.
  • chr(int(d[i:i+8],2)) - konvertiert das aktuelle Segment (d[i:i+8]) von binär in dezimal (int(..., 2)) und dann in ein unformatiertes Zeichen (chr(...))
  • [ x for y in z] - Listenverständnis
  • ''.join(...) - konvertiert die Liste der Zeichen in eine einzelne Zeichenfolge
  • print(...) - drucke es aus
2
Attie

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, input.txt enthält Ihre Daten und ist auf 32 Zeichen pro Zeile formatiert.

Dies verwendet das Python 3-Paket struct und schreibt/liest nach stdin/out. (In Python 2 wäre es kürzer gewesen).

1
wvxvw