小ネタです。
久しぶりのワンライナーです。

ワンライナー

今回ご紹介するワンライナーはこちらです。

cat binary.txt | awk -F# '{print $1}' | grep -s "[0-9a-f]" | sed -e 's/^ *//g' -e 's/ *$//g' -e 's/\ /\\x/g' -e 's/^/\\x/g' -e 's/x/\\x/g' | xargs -I{} echo -en {} > HelloWorld.class

(10/12 追記)
@greymd さんのコメントを元にワンライナーを改良しました!だいぶすっきりしています。

cat binary.txt | awk -F# '{print $1}' | tr -dc [0-9a-f] | xxd -r -p > HelloWorld.class

(/追記)

テキストファイルに16進数で書いたバイト列を読み取ってバイナリファイルを作ってくれるというやつです。
ちょっとバイナリファイルを手打ちで作りたいなー、という需要が個人的にあったので作ってみました。

使い方

まずはインプットとなるbinary.txtファイルをテキストファイルとして準備します。1

binary.txt
ca fe ba be 00 00 00 34 00 1d 0a 00 06 00 0f 09
00 10 00 11 08 00 12 0a 00 13 00 14 07 00 15 07
00 16 01 00 06 3c 69 6e 69 74 3e 01 00 03 28 29
56 01 00 04 43 6f 64 65 01 00 0f 4c 69 6e 65 4e
75 6d 62 65 72 54 61 62 6c 65 01 00 04 6d 61 69
6e 01 00 16 28 5b 4c 6a 61 76 61 2f 6c 61 6e 67
2f 53 74 72 69 6e 67 3b 29 56 01 00 0a 53 6f 75
72 63 65 46 69 6c 65 01 00 0f 48 65 6c 6c 6f 57
6f 72 6c 64 2e 6a 61 76 61 0c 00 07 00 08 07 00
17 0c 00 18 00 19 01 00 0b 68 65 6c 6c 6f 20 77
6f 72 6c 64 07 00 1a 0c 00 1b 00 1c 01 00 0a 48
65 6c 6c 6f 57 6f 72 6c 64 01 00 10 6a 61 76 61
2f 6c 61 6e 67 2f 4f 62 6a 65 63 74 01 00 10 6a
61 76 61 2f 6c 61 6e 67 2f 53 79 73 74 65 6d 01
00 03 6f 75 74 01 00 15 4c 6a 61 76 61 2f 69 6f
2f 50 72 69 6e 74 53 74 72 65 61 6d 3b 01 00 13
6a 61 76 61 2f 69 6f 2f 50 72 69 6e 74 53 74 72
65 61 6d 01 00 07 70 72 69 6e 74 6c 6e 01 00 15
28 4c 6a 61 76 61 2f 6c 61 6e 67 2f 53 74 72 69
6e 67 3b 29 56 00 20 00 05 00 06 00 00 00 00 00
02 00 00 00 07 00 08 00 01 00 09 00 00 00 1d 00
01 00 01 00 00 00 05 2a b7 00 01 b1 00 00 00 01
00 0a 00 00 00 06 00 01 00 00 00 01 00 09 00 0b
00 0c 00 01 00 09 00 00 00 25 00 02 00 01 00 00
00 09 b2 00 02 12 03 b6 00 04 b1 00 00 00 01 00
0a 00 00 00 0a 00 02 00 00 00 03 00 08 00 04 00
01 00 0d 00 00 00 02 00 0e

これを、さきほどのワンライナーを使ってバイナリファイルに変換します。

cat binary.txt | awk -F# '{print $1}' | tr -dc [0-9a-f] | xxd -r -p > HelloWorld.class

これで、インプットに指定したbinary.txtに記載されたバイト列からなるバイナリファイルを作ることができました。名前はHelloWorld.classとしています。

Javaのクラスファイルですので、javaコマンドで実行してみましょう。

$ java HelloWorld 
hello world

ちゃんとjavaコマンドで読み取れましたね。

ちょっとした機能紹介

さて、このワンライナーですが、以下の2点を少し工夫しています。

  • 任意の位置で改行できる(改行はアウトプットに反映されない)
  • 行末にコメントを入れられる

このおかげで、

binary.txt
ca fe ba be  # 最初はマジックナンバー

00 00 00 34 00 1d 0a 00 06 00 0f 09 00 10 00 11 
08 00 12 0a 00 13 00 14 07 00 15 07 00 16 01 00 

... 省略...

48 65 6c 6c 6f 57 6f 72 6c 64  # この部分にクラス名

2e 6a 61 76 61 0c 00 07 00 08 07 00 17 0c 00 18 
00 19 01 00 0b

68 65 6c 6c 6f 20 77 6f 72 6c 64  # この部分に"hello world"

... 省略...

0a 00 00 00 0a 00 02 00 00 00 03 00 08 00 04 00
01 00 0d 00 00 00 02 00 0e

のように、行を良いところで区切ったりコメントを入れることによってアウトプットしたいバイナリファイルの内容を人間の目にも見やすく、また修正しやすくなっています。

作りたいバイナリファイルのフォーマットを確認しながら手打ちできたりもして何かと便利です。個人的に。

まとめ

byte[]がマイブームです。

11/21 追記

このワンライナーを使ってBitmap画像を作ってみよう!という記事を書いて公開しました。
この記事で紹介したワンライナーがバイナリデータの勉強にとても便利に使えることが書かれていますので、ぜひ読んでみてください。

【バイナリファイル入門】Bitmapファイルを手書きで作って遊んでみる



  1. これはこの記事の利用例のためにJavaのHelloWorld.classファイルからxxdコマンド使ったりしてバイト列部分だけを抽出したものです。さすがにこの量を手打ちはできません。