Perl作成者のLarry Wallは、コマンドライン用に緻密な言語設計をしていたのでしょうか。
ワンライナーPerlのパワフルさには、使用の度に感動を覚えるほどです。
Perlでバイナリ処理を書くのは、テキスト処理のように完結にというわけには行きませんが、他コマンドと連携し、バイナリもテキストに置き換えてしまえば、結局はPerlの独壇場となります。
まずは、perl/odの相互変換の説明をするため、32Byteのバイナリファイルa.binを生成したいと思います。やはりperlを使います。
takk~$ seq 32 | perl -ne 'print chr' > a.bin takk~$
これで32Byteのバイナリデータが格納されたファイルが生成されました。
seqコマンドで数列1〜32を生成した結果をパイプでperlに渡します。そしてperlにて、渡された「数字」を「数値」に変換しています。意図したデータとなっているか、a.binをメモリダンプして確認してみましょう。
takk~$ od -tx1 -Ax a.bin 000000 01 02 03 04 05 06 07 08 09 0a 0b 0c 0d 0e 0f 10 000010 11 12 13 14 15 16 17 18 19 1a 1b 1c 1d 1e 1f 20 000020 takk~$
16進で01〜20まで格納されていますね。
さて、odで16進ダンプしたわけですが、これをperlでバイナリに戻してみます。ただし、上記の様なodの結果では、perlで必要のないデータまで入ってしまいます。アドレスを削除し、1Byte毎に改行する表示になるようにオプションを変えてみます。
takk~$ od -tx1 -An -w1 -v a.bin | sed 's/ //' 01 02 03 04 05 06 07 08 09 0a 0b 0c (以下省略)
これでほしい表示となりましたが、このようなフォーマットで出力させることが最初から判っているなら、odコマンドよりもhexdumpコマンドを使う方がスマートです。
takk~$ hexdump -ve '/1 "%02x\n"' a.bin 01 02 03 04 05 06 07 08 09 0a 0b 0c (以下省略)
若干すっきりしました。perlで読み込んでバイナリに戻してみます。
takk~$ hexdump -ve '/1 "%02x\n" a.bin | perl -ne 'print chr hex' > b.bin takk~$ od -tx1 -Ax b.bin 000000 01 02 03 04 05 06 07 08 09 0a 0b 0c 0d 0e 0f 10 000010 11 12 13 14 15 16 17 18 19 1a 1b 1c 1d 1e 1f 20 000020 takk~$ cmp a.bin b.bin takk~$
perlでは、16進10進数変換と数値変換をしています。-neは標準入力を使ってテキスト全行処理する(ただし自動でprintしない)オプションとなります。生成されたb.binは、cmpコマンドにてバイナリ比較をしています。結果表示がないのは、完全一致の意味です。
ちなみに、hexdumpで16進表示にして、わざわざperlでhex関数を使うことにより値を10進に戻していますが、以下のように10進数のまま処理しても問題ありません。
hexdump -ve '/1 "%0u\n" a.bin | perl -ne 'print chr' > b.bin
さて、これだけではやっていることがcpコマンドと同じなので、あまり面白くありません。次は、a.binのデータを1Byteそれぞれを2倍にしてb.binに格納してみます。
takk~$ hexdump -ve '/1 "%02x\n" a.bin | perl -ne 'print chr 2 * hex' > b.bin takk~$ od -tx1 -Ax b.bin 000000 02 04 06 08 0a 0c 0e 10 12 14 16 18 1a 1c 1e 20 000010 22 24 26 28 2a 2c 2e 30 32 34 36 38 3a 3c 3e 40 000020 takk~$
どうでしょうか。各Byteデータが2倍になっているはずです。
段組して10進表記にて確認してみます。
takk~$ od -td1 -An -w1 *.bin | pr -t2J | sed 's/\t\t /=>/' | pr -t4J 1=> 2 9=>18 17=>34 25=>50 2=> 4 10=>20 18=>36 26=>52 3=> 6 11=>22 19=>38 27=>54 4=> 8 12=>24 20=>40 28=>56 5=>10 13=>26 21=>42 29=>58 6=>12 14=>28 22=>44 30=>60 7=>14 15=>30 23=>46 31=>62 8=>16 16=>32 24=>48 32=>64 takk~$
それぞれの数は正しく2倍になっていますね。
コメント