sed-4.0.7のアドレス拡張(STEP)

GNU sedはアドレスにステップを指定できる。指定方法はアドレスんところを'~'とするだけ。
これを使うと簡単に「何行ごとになんとか」ができるのでたとえばプログラムからのダム出力をN行ごとに区切ったりとか出来る。

% sed '1~3i---' eplx.out
---
  77050000 pl_out:  000000
  77100000 pl_out:  000000
  84600000 pl_out:  000110
---
  84650000 pl_out:  000110
  86000000 pl_out:  000101
  86050000 pl_out:  000101
---
  87400000 pl_out:  000100
  87450000 pl_out:  000100
    :

とかできて便利。なんだけど、んんん、なんか一行目の --- 邪魔だぞ、とか思い始めたのが思えば転落開始のサインだった。

% sed '4~3i---' eplx.out
  77050000 pl_out:  000000
  77100000 pl_out:  000000
  84600000 pl_out:  000110
  84650000 pl_out:  000110
  86000000 pl_out:  000101
  86050000 pl_out:  000101
---
  87400000 pl_out:  000100
  87450000 pl_out:  000100
   :

あれれれれれれっれれれっれっれっれっっ?なんで4行目出ないの?

実はライセンスの関係でEDAマシン上でやっていたのだけれど、sedのバージョンが 4.0.7だった。しかしこの仕様、まったくもって、なんじゃこりゃー、とカッとなって思わずソースを拾ってみてしまった。

    case addr_is_num_mod:
      if (addr->addr_number < addr->addr_step)
         return (addr->addr_number == input->line_number%addr->addr_step);
      /* addr_number >= step implies we have an extra initial skip */  // ← 犯人
      if (input->line_number < addr->addr_number)                      // ← 犯人
         return FALSE;
      /* normalize */
      addr->addr_number %= addr->addr_step;
      return (addr->addr_number == 0);

なんじゃこりゃー。

無論、新しいバージョンではちゃんと普通に直ってます。

    case ADDR_IS_NUM_MOD:
      return (input->line_number >= addr->addr_number
          && ((input->line_number - addr->addr_number) % addr->addr_step) == 0);

前のはどういう思想だったんだろう? 激しく気になる*1
で、肝心の対処方法は

% sed '3~3a---' eplx.out
  77050000 hoge:  000000
  77100000 hoge:  000000
  84900000 hoge:  000110
---
  84950000 hoge:  000110
  86300000 hoge:  000101
  86350000 hoge:  000101
---
  87700000 hoge:  000100

でした(最初っからそうせい!)

追記:
ようやく理解した。前のは mod範囲aを指定して、そのうちのオフセット b の位置でマッチ、という考え方だったのか。
なーるほどねえ。それはそれでありか。

*1:単なる馬鹿でしたーだと楽なんだけど