web-dev-qa-db-ja.com

ビットのテキストファイルをバイナリファイルに変換

内容の入ったファイルinstructions.txtがあります。

00000000000000000000000000010011
00000010110100010010000010000011
00000000011100110000001010110011
00000000011100110000010000110011
00000000011100110110010010110011
00000000000000000000000000010011

instructions.binと同じデータのバイナリファイルinstructions.txtを作成するにはどうすればいいですか。言い換えれば、.binファイルは、.txtファイルにあるのと同じ192ビットで、1行あたり32ビットであるべきです。私はUbuntu Linux上でbashを使用しています。私はxxd -b instructions.txtを使用しようとしていましたが、出力は192ビットよりずっと長いです。

10
dopamane

1と0の32ビット文字列を対応するバイナリに変換するoneliner:

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

それがすること:

  • Perl -neは、STDINで提供される入力ファイルの各行を反復処理します(instructions.txt
  • pack("B32", $_)は32ビットの文字列リスト($_ STDINから読み取ったもの)を取り、それをバイナリ値に変換します(ビットの順序を昇順にしたい場合は、代わりに"b32"を使用できます)ビットの降順ではなく各バイト。詳細については、perldoc -f packを参照してください)
  • printは変換された値をSTDOUTに出力し、バイナリファイルにリダイレクトしますinstructions.bin

確認:

$ 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

-rxxd -bオプション(リバースモード)を追加しても、実際には意図したとおりには機能しません。xxdはこれら2つのフラグの組み合わせをサポートしていないためです(両方が指定されている場合-bは無視されます)代わりに、まず自分でビットを16進数に変換する必要があります。例えばこんな感じ:

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

詳しい説明:

  • 括弧内の部分はbcスクリプトを作成します。最初に入力基数を2進数(2)に、出力基数を16進数(16)に設定します。その後、sedコマンドは、4ビットの各グループの間にセミコロンを入れてinstructions.txtの内容を出力します。これは1つの16進数に対応します。結果はbcにパイプされます。
  • セミコロンはbc内のコマンド区切り文字なので、すべてのスクリプトは(整数変換後に)すべての入力整数を出力します。
  • bcの出力は一連の16進数で、通常のxxd -r -pを使用してファイルに変換できます。

出力:

$ 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

私の 元の答え は正しくありませんでした - xxd-pまたは-rのいずれも-b...を受け入れることができません.

他の答えが実行可能であること、そして "別の方法"の利益のために、以下はどうでしょうか。

入力

$ cat instructions.txt
00000000000000000000000000010011
00000010110100010010000010000011
00000000011100110000001010110011
00000000011100110000010000110011
00000000011100110110010010110011
00000000000000000000000000010011

出力

$ 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パイプライン:

cat instructions.txt \
    | tr -d $'\n' \
    | while read -N 4 nibble; do 
        printf '%x' "$((2#${nibble}))"; \
      done \
    | xxd -r -p \
    > instructions.bin
  • cat - 不要ですが、わかりやすくするために使用されます
  • tr -d $'\n' - 入力からすべての改行を削除
  • read -N 4 nibble - 正確に4×文字をnibble変数に読み込む
  • printf '%x' "$((2#${nibble}))"ニブルを2進数から1×16進数文字に変換します
    • $((2#...)) - 与えられた値を2進数(2進数)から10進数(10進数)に変換する
    • printf '%x' - 与えられた値を基数10(10進数)から基数16(16進数)の範囲でフォーマットします。
  • xxd -r -p - プレーンダンプ(-r)を反転(-p) - 16進数から生のバイナリに

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
  • 引用符で囲まれていない heredoc<< EOF)は、Pythonコードにコンテンツを入れるために使用されます
    • 入力が大きくなるとこれは非効率的です
  • cattr - きれいな(1行の)入力を得るために使われます
  • range(0, len(d), 8) - 0から文字列dの終わりまでの数値のリストを取得します。
  • chr(int(d[i:i+8],2)) - 現在のスライス(d[i:i+8])を2進数から10進数(int(..., 2))、次に生の文字(chr(...))に変換します
  • [ x for y in z] - リスト内包表記
  • ''.join(...) - 文字のリストを単一の文字列に変換する
  • print(...) - 印刷する
2
Attie

これをCodeGolf SEサイトに投稿してみるのもいいかもしれませんが、これは私の代わりのPythonバージョンです(キックチャレンジのためだけに):

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

input.txtにあなたのデータが含まれていて、それが1行につき32文字にフォーマットされていると仮定します。

これはPython 3のstructパッケージとstdin/outへの読み書きを使います。 (Python 2ではもっと短くなったでしょう)。

1
wvxvw