linuxだと、odにしてもhdにしても、同じ値が連続していると、途中のダンプ表示が省略できます。しかも省略するのにオプションは要らないので、とても便利です。
takk@deb9:~/tmp$ truncate -s 100 a.bin takk@deb9:~/tmp$ od a.bin 0000000 000000 000000 000000 000000 000000 000000 000000 000000 * 0000140 000000 000000 0000144 takk@deb9:~/tmp$ hd a.bin 00000000 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |................| * 00000064 takk@deb9:~/tmp$
どのような条件で省略されるのでしょうか。
作りやすさから考えると、行を表示する前に、前行と同じかチェックして、*を表示するか、値を表示するか決めているのではないかと思いますが。。。
1行 1Byteにして、確認してみます。
takk@deb9:~/tmp$ od -td1 -Ad -w1 a.bin 0000000 0 * 0000100 takk@deb9:~/tmp$
さきほど作ったa.binは、100Byteのオール0なので、1行 1 Byteだと最初だけ値が表示されました。
次は1行2Byte。
takk@deb9:~/tmp$ od -td1 -Ad -w2 a.bin 0000000 0 0 * 0000100 takk@deb9:~/tmp$
同じく一番最後まで省略されました。
takk@deb9:~/tmp$ od -td1 -Ad -w3 a.bin 0000000 0 0 0 * 0000099 0 0000100 takk@deb9:~/tmp$
3Byte毎だと最後の1Byteが余って、前行と比較した結果不一致なので表示された、ということでしょう。
次は先頭に0以外の値を入れてみます。
takk@deb9:~/tmp$ dd of=a.bin bs=1 count=1 conv=notrunc a 1+0 レコード入力 1+0 レコード出力 1 byte copied, 1.37189 s, 0.0 kB/s takk@deb9:~/tmp$
1行 1Byteで確認。
takk@deb9:~/tmp$ od -td1 -Ad -w1 a.bin 0000000 97 0000001 0 * 0000100 takk@deb9:~/tmp$
次は、3Byte目を1Byte目と同じ値にします。
takk@deb9:~/tmp$ dd of=a.bin bs=1 count=1 conv=notrunc seek=2 a 1+0 レコード入力 1+0 レコード出力 1 byte copied, 1.68292 s, 0.0 kB/s takk@deb9:~/tmp$ takk@deb9:~/tmp$ od -td1 -Ad -w1 a.bin 0000000 97 0000001 0 0000002 97 0000003 0 * 0000100 takk@deb9:~/tmp$
1行1Byteだと97 00、97 00と、同じパターンの繰り返しであっても、省略はされてません。
takk@deb9:~/tmp$ od -td1 -Ad -w2 a.bin 0000000 97 0 * 0000004 0 0 * 0000100 takk@deb9:~/tmp$
1行2Byteの表示になることにより、2行目は1行目と一致するので、省略されました。
やはり、行を表示する時に、前回表示した内容と一致しているか判定してるっぽいですね。
では、odのソースで答え合わせをしてみます。coreutilsです。
odの省略表示するかどうかのオプションは、-vですので、オプション解析の定型文case オプション:で検索します。
takk@deb9:~/src/coreutils-8.26/src$ grep 'case.*v' -A3 od.c case '\v': s = "\\v"; break; -- case '\v': fputs ("\\v", stdout); break; -- case 'v': modern = true; abbreviate_duplicate_blocks = false; break; takk@deb9:~/src/coreutils-8.26/src$
-vオプションに該当するのは、一番下にあるcase ‘v’です。このcaseに入った時のフラグであるabbreviate_duplicate_blocksを追いかければ良いですね。
まあ、追いかけるのも面倒いので、やはりgrepです。
takk@deb9:~/src/coreutils-8.26/src$ grep 'abbrevi.*blocks' od.c static bool abbreviate_duplicate_blocks = true; if (abbreviate_duplicate_blocks abbreviate_duplicate_blocks = false; takk@deb9:~/src/coreutils-8.26/src$
ifで判定して使用してる箇所が怪しいので、 前後10行ぐらいを表示してみます。
takk@deb9:~/src/coreutils-8.26/src$ grep 'if.*abbrevi.*blocks' -C10 od.c static void write_block (uintmax_t current_offset, size_t n_bytes, const char *prev_block, const char *curr_block) { static bool first = true; static bool prev_pair_equal = false; #define EQUAL_BLOCKS(b1, b2) (memcmp (b1, b2, bytes_per_block) == 0) if (abbreviate_duplicate_blocks && !first && n_bytes == bytes_per_block && EQUAL_BLOCKS (prev_block, curr_block)) { if (prev_pair_equal) { /* The two preceding blocks were equal, and the current block is the same as the last one, so print nothing. */ } else { takk@deb9:~/src/coreutils-8.26/src$
予想通りでした。
前のブロック(prev_block)と、今のブロック(curr_block)を比較してます。
EQUAL_BLOCKSというマクロを直前に定義しているのが面白いです。敢えてマクロを書くというテクニック、私的には大収穫です。
コメント