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.

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

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

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

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

Korzystając z naszej strony potwierdzasz, że przeczytałeś(-aś) i rozumiesz nasze zasady używania plików cookie i zasady ochrony prywatności.
Licensed under cc by-sa 3.0 with attribution required.