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


12

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

00000000000000000000000000010011
00000010110100010010000010000011
00000000011100110000001010110011
00000000011100110000010000110011
00000000011100110110010010110011
00000000000000000000000000010011

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

回答:


6

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

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

それがすること:

  • perl -neSTDIN(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  ....

8

-rオプション(リバースモード)をに追加しxxd -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)に、出力ベースを16進数(16)に設定します。その後、sedコマンドは、instructions.txt4ビットの各グループの間にセミコロンを付けて内容を出力します。これは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  ....

申し訳ありませんが、これにはまだエンディアンのバグがあります。修正に取り組んでいます!
nomadictype 2018年

1
実は大丈夫です。最後のxxdコマンドで誤った出力幅を使用することにより、以前は混乱していました。
nomadictype 2018年

1
スクリプトをテストしましたが、機能しますが次のように出力されます(standard_in) 1: syntax errorsyntax errorそれが何を参照しているか、なぜこれが発生するのか説明できますか?これはあなたのマシンでも起こりますか?
dopamane '10 / 10/18

2

私の元の答えは間違っていました- 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- 正確に 4x文字をnibble変数に読み込みます
  • printf '%x' "$((2#${nibble}))" ニブルをバイナリから1×16進文字に変換します
    • $((2#...)) -指定された値を基数2(バイナリ)から基数10(10進数)に変換します
    • printf '%x' -指定された値を10進数(10進数)から16進数(16進数)にフォーマットします
  • xxd -r -p-リバース(-r)プレーンダンプ(-p)-16進数からrawバイナリへ

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コードにコンテンツを取得するために使用されます
    • 入力が大きくなると、これは効率的ではありません
  • catおよびtr-クリーンな(1行の)入力を取得するために使用
  • range(0, len(d), 8)-0から文字列の末尾までの数字のリストを取得dし、一度に8文字ずつステップします。
  • chr(int(d[i:i+8],2))-現在のスライス(d[i:i+8])を2進数から10進数(int(..., 2))に変換し、次に生の文字(chr(...))に変換します
  • [ x for y in z]- リストの理解
  • ''.join(...) -文字のリストを単一の文字列に変換します
  • print(...) -印刷する

1
注:多くのシェル|では、行の終わりでバックスラッシュのように機能します。コマンドは次の行に続きます。この方法で、いくつかのバックスラッシュを取り除くことができます。LFの後にパイプシンボルを使用することがあなたの情報に基づいた決定であったかどうかはわかりません。あなたが知らなかった場合に備えて、私は他の方法について言及しています。
カミルMaciorowski、

1
知らなかった、ありがとう!パイプラインを論理的な線に分割し、パイプ|(またはリダイレクト>、ブール演算子&&など)を明示的に前面に配置して、可視性/明快さを求めます。
2018年

1
少し考えてから、この2つの線のいずれかを調べることで、2つの線が接続されていることがわかるので、このスタイルを使い始めるかもしれません。場合は|末尾にある、次の行は、それが混乱することができるスタンドアロンのコマンドのように見えることがあります。これが、このスタイルがあなたの情報に基づいた決定かもしれないと思った理由です。
Kamil Maciorowski、

すばらしいです。どうなるか教えてください:-)
Attie

1
それは起こって。:)
カミルMaciorowski

1

これを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では短くなっていました)。

弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.