nlコマンドの細かい仕様を調べていくと最大値や最小値も気になりますね。実装ごとの仕様やエラーについてまとめておこうと思います。
行番号
つまり何行まで数えられるかということです。BSD系のnlではデフォルトの桁数がボトルネックになることは以前も確認しましたが、今回は「行数」の最大値を見ていきます。また、x86_64(AMD64)のアーキテクチャで検証していますので、環境によっては異なる可能性もあると思います。
GNU coreutils
$ yes unko | nl -v 9223372036854775806
9223372036854775806 unko
9223372036854775807 nl: line number overflow
coreutilsのnl
では符号付き64bitのようです。9,223,372,036,854,775,807
が最大値と言いたいところですが、厳密にはunko
を出し切らずにオーバーフローでエラーになっています。しかしこの中途半端なエラーも2020年10月の修正のついでに改善されているので、次版(v8.33?)以降では最後まで出し切ってからエラーになります。
$ yes unko | nl -v 9223372036854775806
9223372036854775806 unko
9223372036854775807 unko
nl: line number overflow
どの行でオーバーフローしたのかが明確になるので、少々デバッグが楽になるんじゃないかと思います。900京行超えのテキストファイルなんて絶対触りたくないですけどね。
BSD系
$ yes unko | nl -v 2147483647 -w 11 | head -2
2147483647 unko
-2147483648 unko
BSD系のnl
では符号付き32bitのようです。つまり2,147,483,647
が最大です。
そしてオーバーフローしません。そのまま符号がひっくり返ってカウントを続けます。つまり正しい行番号を出力しませんが、エラーが発生して終了することもありません。
busybox
busyboxはちょっとおもしろい挙動です。また、負の値には対応していません。
$ yes unko | busybox nl -v 2147483648 | head
nl: number 2147483648 is not in 0..2147483647 range
オプションに大きな数を指定するとエラーになります。符号付き32bitの正の値だけが有効のようです。しかし、実際に使ってみると上限はほかのところにあります。
$ yes unko | busybox nl -v 2147483647 | head -n 2147483647 | tail
4294967284 unko
4294967285 unko
4294967286 unko
4294967287 unko
4294967288 unko
4294967289 unko
4294967290 unko
4294967291 unko
4294967292 unko
4294967293 unko
あまり厳密ではありませんが(回しっぱなしにしてみたら超時間かかったのでやり直したくない)、符号なし32bitまではカウントできるようです。
変数の型を確認する
実行が中途半端になってしまったので、代わりにbusyboxのソースを確認しましょう。
まずは、-vオプションの引数処理です。
https://github.com/mirror/busybox/blob/master/coreutils/nl.c
getopt32long(argv, "pw:+s:v:+i:+b:", nl_longopts,
&ns.width, &ns.sep, &ns.start, &ns.inc, &opt_b);
pw:+s:v:+i:+b:
のv:+
という部分が、-v
の識別子ですね。
https://github.com/mirror/busybox/blob/master/libbb/getopt32.c
"o:+" This means that the parameter for this option is a nonnegative integer.
It will be processed with xatoi_positive() - allowed range
is 0..INT_MAX.
こちらを確認すると、:+
は0..INT_MAX
ということのようです。
あとは行番号の処理も見ましょう。ちなみにbusyboxではこの処理はcat -n
と共通です。
https://github.com/mirror/busybox/blob/master/libbb/print_numbered_lines.c
void FAST_FUNC print_numbered_lines(struct number_state *ns, const char *filename)
{
FILE *fp = fopen_or_warn_stdin(filename);
unsigned N = ns->start;
unsigned N
がカウンタの変数です。つまり、オプションを取得する関数内で正の数に制限されているだけで、カウンタ自体は2倍のunsigned
までカウントできるようです。
#エラー
もしシェルスクリプトなどでエラー処理を書く場合は、戻り値(終了ステータス)を見ることになります。bash
では戻り値が変数$?
に格納されるので、それを確認することもできます。
POSIX
EXIT STATUS
The following exit values shall be returned:
0
Successful completion.
>0
An error occurred.
POSIXでは成功した場合は0
、エラーは0より大きい
と決められています。各実装でエラーのときどんな値が返ってくるのか見てみましょう。存在しないオプションを実行してみます。
GNU coreutils
$ nl -a &>/dev/null || echo $?
1
busybox
$ busybox nl -a &>/dev/null || echo $?
1
BSD系
$ nl -a &>/dev/null || echo $?
1
どれも1
が返ってきました。