przekonwertować plik tekstowy bitów na plik binarny

12

Mam plik instructions.txtz zawartością:

00000000000000000000000000010011
00000010110100010010000010000011
00000000011100110000001010110011
00000000011100110000010000110011
00000000011100110110010010110011
00000000000000000000000000010011

Jak mogę utworzyć plik binarny instructions.binz tymi samymi danymi co instructions.txt. Innymi słowy, .binplik powinien mieć te same 192 bity, które są w .txtpliku, z 32 bitami na linię. Używam bash na Ubuntu Linux. Próbowałem użyć, xxd -b instructions.txtale wyjście jest znacznie dłuższe niż 192 bity.

dopamane
źródło

Odpowiedzi:

6

oneliner konwertuje 32-bitowe ciągi zer i jedynek na odpowiednie pliki binarne:

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

co to robi:

  • perl -newykona iterację w każdym wierszu pliku wejściowego podanego w STDIN ( instructions.txt)
  • pack("B32", $_)weźmie listę 32 bitów ( $_którą właśnie odczytaliśmy ze STDIN) i skonwertuje ją na wartość binarną (możesz alternatywnie użyć, "b32"jeśli chcesz rosnącą kolejność bitów wewnątrz każdego bajtu zamiast malejącej kolejności bitów; zobacz perldoc -f packwięcej szczegółów)
  • print wyśle ​​następnie przekonwertowaną wartość na STDOUT, którą następnie przekierujemy do naszego pliku binarnego instructions.bin

zweryfikować:

$ 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
źródło
8

Dodanie -ropcji (tryb odwrotny) xxd -bnie działa tak, jak powinno, ponieważ xxd po prostu nie obsługuje łączenia tych dwóch flag (ignoruje, -bjeśli podano obie). Zamiast tego musisz najpierw przekonwertować bity, aby przeklęły się same. Na przykład tak:

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

Pełne wyjaśnienie:

  • Część w nawiasach tworzy bcskrypt. Najpierw ustawia bazę wejściową na binarną (2), a bazę wyjściową na szesnastkową (16). Następnie sedpolecenie drukuje zawartość instructions.txtśrednika między każdą grupą 4 bitów, co odpowiada 1 cyfrze szesnastkowej. Wynik jest przesyłany do bc.
  • Średnik jest separatorem poleceń bc, więc skrypt wykonuje wypisywanie wszystkich liczb całkowitych wejściowych z powrotem (po konwersji podstawowej).
  • Wynikiem bcjest ciąg cyfr szesnastkowych, który można przekonwertować do pliku za pomocą zwykłego pliku xxd -r -p.

Wynik:

$ 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  ....
koczownik
źródło
Przepraszamy, wciąż występuje w tym błąd endianizmu. Pracuję nad naprawą!
nomadictype 10.10.18
1
Właściwie to jest w porządku. Byłem zdezorientowany wcześniej, używając niewłaściwej szerokości wyjściowej w ostatnim poleceniu xxd.
nomadictype 10.10.2018
1
Przetestowałem skrypt i działa, ale wyjść: (standard_in) 1: syntax error. Czy możesz wyjaśnić, do czego syntax errorto się odnosi lub dlaczego tak się dzieje? Czy zdarza się to również na twoim komputerze?
dopamane
2

Mój oryginalny odpowiedź była błędna - xxdnie może zaakceptować albo -plub -rz -b...

Biorąc pod uwagę, że inne odpowiedzi są wykonalne, i w interesie „ innej drogi ”, co powiesz na następujące kwestie:

Wejście

$ cat instructions.txt
00000000000000000000000000010011
00000010110100010010000010000011
00000000011100110000001010110011
00000000011100110000010000110011
00000000011100110110010010110011
00000000000000000000000000010011

Wynik

$ 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

Rurociąg Bash:

cat instructions.txt \
    | tr -d $'\n' \
    | while read -N 4 nibble; do 
        printf '%x' "$((2#${nibble}))"; \
      done \
    | xxd -r -p \
    > instructions.bin
  • cat - niepotrzebne, ale używane dla zachowania przejrzystości
  • tr -d $'\n' - usuń wszystkie znaki nowej linii z wejścia
  • read -N 4 nibble- wczytaj dokładnie 4 × znaki do nibblezmiennej
  • printf '%x' "$((2#${nibble}))" przekonwertować nibble ze znaku binarnego na 1 × hex
    • $((2#...)) - przekonwertuj podaną wartość z podstawy 2 (binarnie) na podstawę 10 (dziesiętnie)
    • printf '%x' - sformatuj podaną wartość od podstawy 10 (dziesiętnie) do podstawy 16 (szesnastkowo)
  • xxd -r -p- reverse ( -r) zwykły zrzut ( -p) - od szesnastkowego do surowego pliku binarnego

Pyton:

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
  • Niecytowana heredoc ( << EOF) służy do pobierania treści do kodu Pythona
    • Nie jest to wydajne, jeśli dane wejściowe stają się duże
  • catoraz tr- służy do uzyskania czystego (jednowierszowego) wejścia
  • range(0, len(d), 8)- uzyskaj listę liczb od 0 do końca ciągu d, z krokiem 8 × znaków naraz.
  • chr(int(d[i:i+8],2))- przekonwertuj bieżący wycinek ( d[i:i+8]) z binarnego na dziesiętny ( int(..., 2)), a następnie na surowy znak ( chr(...))
  • [ x for y in z]- zrozumienie listy
  • ''.join(...) - przekształca listę znaków w pojedynczy ciąg
  • print(...) - Wydrukuj to
Attie
źródło
1
Uwaga: w wielu powłokach |na końcu linii działa jak ukośnik odwrotny: polecenie przechodzi do następnej linii. W ten sposób możesz pozbyć się kilku ukośników. Nie jestem pewien, czy używanie symboli potoku po LFs było twoją świadomą decyzją. Wspominam o innym sposobie, na wypadek gdybyś nie wiedział.
Kamil Maciorowski,
1
Nie wiedziałem, dzięki! Lubię rozbijać potok na logiczne linie i mieć wyraźnie potoki |(lub przekierowania >, operatory logiczne &&itp.) Wyraźnie z przodu dla widoczności / przejrzystości ... być może stylistycznej / preferencji.
Attie
1
Po namyśle mogę zacząć używać tego stylu, ponieważ można stwierdzić, że dwie linie są połączone, badając dowolną z nich. Jeśli |jest na końcu, następny wiersz może wyglądać jak samodzielne polecenie, może być mylące. Właśnie dlatego pomyślałem, że styl może być twoją świadomą decyzją.
Kamil Maciorowski,
Niesamowite, daj mi znać, jak to idzie :-)
Attie
1
Będzie dobrze . :)
Kamil Maciorowski
1

Równie dobrze możesz opublikować to na stronie CodeGolf SE, ale oto moja alternatywna wersja Pythona (tylko na wyzwanie kopnięcia):

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

Zakładając, że input.txtzawiera dane, jest sformatowany do 32 znaków w wierszu.

Używa to structpakietu Python 3 i zapisuje / odczytuje do wejścia / wyjścia. (W Pythonie 2 byłoby to krótsze).

wvxvw
źródło