これは驚くべき事実なのですが、nl
には論理ページを無効にする方法が定義されていません。ほとんどの人が論理ページを意識しない使い方をしているにもかかわらずです。
(前提とする知識)
論理ページの不都合な真実
nl
の論理ページ機能は、\:
など特定のパターン行からセクションを識別しているため入力データに依存しています。そしてnl
に論理ページを無効にする機能がないということは、ユーザーは入力するデータに意図しない区切り文字列(デフォルト\:
)が出現しないことを常に保証しなければなりません。データに意図しない区切り文字列が含まれることが判明した場合、セクションの区切りとして認識されることを回避するために、データ中に含まれない任意の文字列(BSD系のnl
なら最大2文字)を特定し-dオプションに指定する必要があります。
実際の影響としては、入力データに区切り文字列が発生した時点で、行番号がリセットされてしまいます。この影響は-pオプションを利用すればセクション区切りでリセットされないようにできるので、影響を小さくすることができます。しかし、区切り文字が削除あるいは空行に変換される分、行番号に誤りが発生すること、そして区切り文字列そのものの消失を防ぐことはできません。
特に、入力データがユーザーの制御下にない場合はどうすることもできません。区切り文字列が入力されないことをただ祈るのみです。ていうか誰がそこまで行番号つけるのに本気出すんだよ
論理ページの無効化戦略
BSD系のnl
残念ですが諦めてください。区切り文字列は2文字に限定されていますので、その範囲内で最も出現しなさそうな2文字の順列を選ぶ以外にありません。
busyboxのnl
busyboxは論理ページに対応していません。つまりこのnl
を利用することで論理ページを無効化することができます。やったー!
GNU coreutilsのnl
長いユニークな文字列を区切り文字列に設定する
-d
のGNU拡張を用いれば長い文字列を区切り文字列に設定できるので、ユニークな区切り文字列を設定することはできそうです。しかし確率を下げる長い文字列にする以外ありません。以下のようにランダムな長い文字列を生成して利用する感じになりそうです。
$ cat /dev/urandom | tr -dc '0-z' | fold -w 64 | head -n 1
jp9NgI3a7Hx][wmk[qlMgmCoOcuhbm9Sx>W:ZC2e:rd^bsI]at95u0JkAUokZv2Q
$ echo -e 'a\n\:\nb' | nl -d 'jp9NgI3a7Hx][wmk[qlMgmCoOcuhbm9Sx>W:ZC2e:rd^bsI]at95u0JkAUokZv2Q'
1 a
2 \:
3 b
これはちょっと嫌ですね。ランダム文字列の生成にシェルのコマンド置換を用いたほうがわかりやすくなります。
$ echo -e 'a\n\:\nb' | nl -d $(cat /dev/urandom | tr -dc '0-z' | fold -w 64 | head -n 1)
1 a
2 \:
3 b
しかしこれだと毎回文字列が変わってしまうので、万が一セクション区切りが発生した場合には、原因追求が難しくなりそうです。
空文字列を区切り文字列に設定する
現時点でこれは完全にバグ技です。この不具合を利用します。
$ echo -e 'a\n\:\nb' | nl -d ''
1 a
2 \:
3 b
非常にシンプルに書けますね。次版(v8.33?)からは不具合が修正され正式なGNU拡張としてTexinfoにも記載されるようになりますので、この方法が正攻法になります。
As a GNU extension more than two characters can be specified,
and also if CD is empty (-d ''), then section matching is disabled.
余談
上記の不具合修正ならびにドキュメント化の対応にあたっては、空文字を与えた場合の動作仕様についてしかるべき議論はなされたと思います。空文字の場合はデフォルトの\:
としたほうが一貫性があるという意見もありましたが、最終的に論理ページを無効にできる方法をGNU拡張として用意すべきだということでまとまりました。