シェルスクリプトでファイルや標準出力の行頭に連番を付与する「nl」コマンド

2020-01-17Bash

はじめに

Markdownでドキュメントを記述していると「箇条書きリスト」や「数字付きリスト」記法や度々使用します。

例)「箇条書きリスト」記法

* あ
* い
* う
* え
* お

例)「数字付きリスト」記法

1. あ
2. い
3. う
4. え
5. お

さて、この「数字付きリスト」記法と同様のものをシェルで簡単に生成できないか?というのが今回のお話です。

nl コマンドを利用します。

検証環境

$ uname -moi
x86_64 x86_64 GNU/Linux

$ bash -version
GNU bash, version 4.2.46(2)-release (x86_64-redhat-linux-gnu)

$ nl --version
nl (GNU coreutils) 8.22

nl コマンドの使い方

テストデータを出力させます。
yes コマンドを使って xxx という文字を5行出力させます。

$ yes xxx | head -n 5
xxx
xxx
xxx
xxx
xxx

これにMarkdownの「数字付きリスト」のような連番を付与するには以下のようなコマンドを実行します。

$ yes xxx | head -n 5 | nl -w 1 -s '. '
1. xxx
2. xxx
3. xxx
4. xxx
5. xxx

できましたね。
nl コマンドについて少々解説していきます。

nl コマンドとは?

nl コマンドは引数で指定したファイルや標準入力の内容に行番号を追加します。
nl コマンドは GNU Coreutils に含まれています。したがって「macOS」環境の方は以下のコマンドでインストールする必要があります。

( シェルスクリプトでファイルや標準出力を最終行から逆順に出力する方法 を参照 )

$ brew install coreutils \
  --with-default-names

先程のコマンドをオプション無しで実行すると、以下のような結果になります。

$ yes xxx | head -n 5 | nl
     1  xxx
     2  xxx
     3  xxx
     4  xxx
     5  xxx

実は同じような機能は cat コマンドにもあり、 -n オプション付きで実行した場合の挙動と同じです。

$ yes xxx | head -n 5 | cat -n
     1  xxx
     2  xxx
     3  xxx
     4  xxx
     5  xxx

ただし、 nl コマンドにはオプションが豊富にあり、行番号の値の出力方法をいろいろ制御できます。
一部を紹介します。

nl コマンドのオプション

-w オプション

先程のコマンドで利用していたオプションです。
行番号の数値の「幅」を指定します。 *width の頭文字から来ているのでしょう。

例えば、1〜10の行番号を出力したいが、数値の位置を揃えたい場合には -w 2 を指定します。

$ yes xxx | head -n 10 | nl -w 2
 1      xxx
 2      xxx
 3      xxx
 4      xxx
 5      xxx
 6      xxx
 7      xxx
 8      xxx
 9      xxx
10      xxx

こちらは次に紹介する -n オプションと組み合わせて使うと更に便利です。

-n オプション

どのようなフォーマットで数値を出力するかを指定します。
alignn をとったのかな?

-nオプションの引数フォーマット
rn右寄せ(デフォルト)
ln左寄せ
rz右寄せ、ゼロ表示
# 右寄せ
$ yes xxx | head -n 3 | nl -n rn
     1  xxx
     2  xxx
     3  xxx

# 左寄せ
$ yes xxx | head -n 3 | nl -n ln
1       xxx
2       xxx
3       xxx

# ゼロパディング
$ yes xxx | head -n 3 | nl -n rz
000001  xxx
000002  xxx
000003  xxx

3つ目のゼロパディングですが、0を含めて何文字幅にするかを -w オプションで指定できます。

$ yes xxx | head -n 3 | nl -n rz -w 2
01      xxx
02      xxx
03      xxx

さらに -s オプションを組み合わせて、数値と文字の間のフォーマットを変更できます。

-s オプション

-s を使って、数値の連番と元のデータ部分の間の「スペース」を別のフォーマットに変換できます。

suffixs と覚えましょう。

一つ前のコマンドに -s オプションを追加してみましょう。

$ yes xxx | head -n 3 | nl -n rz -w 2 -s ':'
01:xxx
02:xxx
03:xxx

Vimで使う

最初に戻って、Markdownを記述しているときに「数字付きリスト」への変換を行うための方法。
以下のような文字があったとします。

aaa
bbb
ccc

Visualモード で選択し、 :'<,'>!nl -w 1 -s '. ' で以下のような「数値付きリスト」形式に変換できます。

1. aaa
2. bbb
3. ccc

ひとこと

nl コマンドもあまり使うことはないですね。
業務では今の所使ったことがありません。

2020-01-17Bash