指定した複数の行番号に対する文字列処理

sed のアドレス指定は1行の指定や開始行と終了行による範囲指定くらいしかなく,任意の複数行の指定ができない.

そこで,以下のように,単純に行ごとにコマンドを繰り返して sed に流し込んでみた.

$ (for i in `cat LINES`; do echo "${i}SED_COMMANDS"; done) | sed -f - TEXTFILE

この方法は LINES や TEXTFILE が大きくなると劇的に遅くなる.生成する sed スクリプトが肥大化するのはもちろんだが,恐らく sed の内部処理的に TEXTFILE を毎回走査するとかいうアホなことになっているのだろう.もっとうまい方法はないだろうか?

ただ,もし LINES が seq の INCREMENT 指定で生成できるような単純な飛び飛びの値だった場合,GNUsed のアドレス指定 n~s (n 行目から s 行ごと) を使って少し工夫すれば圧倒的に速くなる.

$ seq 1 50000 > a.txt
$ time (for i in `seq 1 2 10000`; do echo "${i}s/^/# /"; done) | sed -f - a.txt > b.txt

real    0m11.718s
user    0m10.424s
sys     0m0.130s

$ time (head -10000 a.txt | sed '1~2s/^/# /'; sed -n '1,10000!p' a.txt) | cat - > c.txt

real    0m0.636s
user    0m0.340s
sys     0m0.160s

$ diff b.txt c.txt
$