コマンドラインツールのショートオプションをどの用途で使うべきか

# はじめに

コマンドラインツールが多数作られるプロジェクトがあるとします。
複数人で開発していると、オプションの意味付けが人によってばらばらになってしまう――そんな事象は、おそらくよくあることだと思います。
ので、そのような環境では、なんらか規約を設けるのがよさそうです。

本記事では、その規約の作成、またはオプションの意味付けにおいて、参考となるであろう情報を提示します。

特に、**ショートオプション**（英字1字のみのオプション）にフォーカスします。
**ロングオプション**（英字複数字から成るオプション）については、意味は自明になることが多いでしょう。
ただし、「ショートオプションをどのロングオプションに対応付けるべきか」という問題は、本稿でも扱います。

また、コマンド文法やオプションのフォーマットはOSやプログラムによって異なりますが、ここでは以下を前提とします：

- ショートオプション ... `-a`, `-b` など「ハイフン + 英字1字」の形式
- ロングオプション ... `--all`, `--binary` など「ハイフンx2 + 英字複数字」の形式

# どのように規約を作るか

以下の2つは、原則となると思います。

* プロジェクト内で、なるべくオプションの意味を統一する。
  * 異なるものがあると、ヒューマンエラーを誘発する、学習コストがかかるなど、いわゆる技術的負債になりかねない。
* 可能な限り、標準的な慣習に従う。
  * 新メンバーが入った時の学習コストを抑えることができる。

後者について、「標準的な慣習」の参考情報は、後の節で示します。
慣習にないオプションをどう扱うか、慣習から外れるオプションをどこまで許容するかは、匙加減が必要そうです。
場合によっては、プロジェクト独自のローカルルールを作った方がいいこともあるかもしれません。

（参考）ローカルルールの例:

* ショートオプションはロングオプションの先頭1字とする。
  * 用途として、慣習的に使われるオプションがあれば、なるべくそれに従う
* そのプログラムに特有のオプション（慣習にないもの）は、どの文字を使ってもいい
* `-h` を `--help` 以外の用途で用いることは避ける
* `-v` を `--verbose` 以外の用途で用いることは避ける

# オプション用途の標準

前節で述べたオプション用途の「標準的な慣習」として、参考になる情報を示します。

調べたところ、Unix ライクシステムで慣習的に使われるショートオプションの意味について、よくまとまっている資料が2つありました：

1. [Command-Line Options / The Art of UNIX Programming](http://catb.org/~esr/writings/taoup/html/ch10s05.html)
  - Eric S. Raymond [^1] が自身のHPで公開している『The Art of UNIX Programming』[^2]の一節です。
  - Unix のプログラムでよく使われるショートオプションがどのような意味を持つか、`-a` から `-z` までまとめられています。
2. [GNU Coding Standards: Option Table](https://www.gnu.org/prep/standards/html_node/Option-Table.html#Option-Table)
  - GNU プログラムで使われるロングオプションがリストアップされています。

両者には共通する項目も多いですが、一方にしか含まれないものも多少、有ります。
そこで、（現時点では）両者をマージした一覧表を作るのではなく、それぞれ主な部分（と筆者が判断したもの）を表にまとめています。

以下の小節で、それぞれを示します。

[^1]: [Eric S. Raymond's Home Page](http://www.catb.org/esr/)
[^2]: http://www.catb.org/~esr/writings/taoup/html/

## The Art of UNIX Programming - Command-Line Options

ここでは、『The Art of UNIX Programming』の [Command-Line Options](http://catb.org/~esr/writings/taoup/html/ch10s05.html) に示されている `-a` to `-z` のショートオプションのよく使われる意味について、簡単に下表にまとめます。

option | 引数 | よく用いられる意味(部分意訳)
:-----:|:---:|-----------------------
a | 無 | all（すべて）。 例) fuser(1), fetchmail(1) 
  | 無 | append（追加）。しばしば "-d" (delete) とペアで用いられる。例) tar(1)
b | 有 | バッファ/ブロックサイズ。例) du(1), df(1), tar(1)
  | 無 | バッチモード。対話プログラムのプロンプトを抑制する。例) flex(1)
c | 有 | コマンド。下の "-e" と対比せよ。例) sh(1), ash(1), bsh(1), ksh(1), python(1)
  | 無 | ファイル引数のチェックを行うが、実行しない。インタプリタの構文チェックによく使われる。例) getty(1), perl(1)
d | 無/有 | デバッグ。デバッグのロギングレベルを設定する。非常に一般的。
  | | delete（削除）
  | | ディレクトリ
D | 有 | 1つまたは複数のシンボルの値を定義する。コンパイラやマクロプロセッサのようなプログラムで使われる。
e | 有 | ラッパープログラムで、実行するプログラムを引数に取る。例) xterm(1), perl(1)
  | | 編集モード。例) crontab(1), get(1)
  | | exclude（除外する）
  | | expression（表現）
f | 有 | ファイルを引数に取る。非常によく使われる。例) tar(1) <br />また、通常コマンドラインから引数を取得するプログラムで、ファイルから引数を取得する際にも使われる。下の "-o" と比較せよ。例) awk(1), egrep(1)
  | 無 | force（強制）。通常条件付きで実行される操作を強制実行する。
h | 無 | ヘッダを有効化、または抑制、または修正する。例) pr(1), ps(1)
  | | ヘルプ。昔はメモリの問題で man を書く人のほうが多かったので、UNIX でそれほど一般的だとはいえない。
i | 無 | initialize（初期化）。プログラムにとって必須のデータセットを用意する。例) ci(1)
  | 無 | interactive（対話的）。プロンプトを要求する。一般的ではない。例) rm(1), mv(1)
I | 有 | include（含める）。ファイルやディレクトリをプログラムのリソースに加える。全てのコンパイラでソースファイルの include の意味で使われる。他の意味で用いられると、極めて意外だ。
k | 無 | keep（保持）。ファイル or メッセージ or リソースの削除を抑制する。例) passwd(1), bzip(1), fetchmail(1)
  | | kill
l | 無 | list（一覧）。ファイルの圧縮や再生を行うプログラムで、アイテムの一覧以外の意味で用いられるのはとても意外だ。例) arc(1), binhex(1), unzip(1)
  | 無 | long. レポート表示プログラムで、長い出力形式を意味する。例) ls(1), ps(1)
  | 有 | load. リンカやインタプリタで、ライブラリを読み込む。例) gcc(1), f77(1), emacs(1)
  | | login ID. 例) rlogin(1), ssh(1)
  | | length
  | | lock
m | 有 | メッセージ。ロギングや通知用途。例) ci(1), cvs(1)
  | | mail
  | | mode
  | | modification-time（修正日時）
n | 有 | number. 例えばページ数の範囲。例) head(1), tail(1), nroff(1), troff(1)
  | 無 | ネットワーク系のプログラムで、DNS名の代わりにIPアドレスを表示する。例) ifconfig(1), tcpdump(1)
  | 無 | not. 通常の動作を抑制する。例) make(1)
o | 有 | output. 出力先ファイルやデバイス。コンパイラのようなプログラムで他用途に用いられるのは極めて意外。例) as(1), cc(1), sort(1)
p | 有 | TCP/IP ポート番号。例) cvs(1), postgres(1), smbclient(1), snmpd(1), ssh(1)
  | 有 | プロトコル。例) fetchmail(1), snmpnetstat(1)
q | 無 | quiet. 出力を抑制する。非常に一般的。"-s" (silent) も参考に。例) ci(1), co(1), make(1)
r(R) | 無 | recurse（再帰）。ディレクトリを処理するプログラムに、サブディレクトリも処理するよう指示する。この種のツールで他の意味で用いられるのは非常に意外。例) cp(1)
     | 無 | reverse. 逆順でフィルタする。"-d" と比べよ。例) ls(1), sort(1)
s | 無 | silent. 出力を抑制する。"-q" と似ているが、両オプションが有効なとき、"-s" は完全に無出力を意味する。例) csplit(1), ex(1), fetchmail(1)
  | 有 | subject（件名）。メールやニュースを送信・操作するもので常にこの意味で使われる。例) mail(1), elm(1), mutt(1)
  | | サイズ
t | 有 | タグ。検索キー。特にテキストエディタやビューワで使われる。例) cvs(1), ex(1), less(1), vi(1)
u | 有 | ユーザ。例) crontab(1), emacs(1), fetchmail(1), fuser(1), ps(1)
v | 無/有 | verbose（冗長）。デバッグログやモニタリングログを有効化する。例) cat(1), cp(1), flex(1), tar(1)
  | 無 | プログラムのバージョンを表示して終了する。"-V" の方がふつう。例) cvs(1), chattr(1), patch(1), uucp(1)
V | 無 | プログラムのバージョンを表示して終了する。ときにコンパイル時の設定を併せて表示する。他用途での利用は非常に意外。例) gcc(1), flex(1), hostname(1)
w | 有 | width. 出力時の幅を指定する。例) faces(1), grops(1), od(1), pr(1), shar(1)
  | 無 | warning. 警告出力を有効、または無効にする。例) fetchmail(1), flex(1), nsgmls(1)
x | 無/有 | デバッグ表示を有効化する（"-d"と同様）。例) sh(1), uucp(1)
  | 有 | extract（抽出）。圧縮ファイルなどから抽出されるファイルを一覧する。例) tar(1), zip(1)
y | 無 | yes. 破壊的操作に対する確認プロンプトを全て許可する。例) fsck(1), rz(1)
z | 無 | 圧縮を有効化する。圧縮・バックアッププログラムでよく使われる。例) bzip(1), GNU tar(1), zcat(1), zip(1), cvs(1)

## GNU Programs - Table of Long Options

ここでは、 [GNU Coding Standards: Option Table](https://www.gnu.org/prep/standards/html_node/Option-Table.html#Option-Table) から、以下の条件に適うものについて抽出し、ショートオプションとロングオプションの対応表を示します。

条件：

- ショートオプションを持つもの
- ロングオプションがプログラム固有でないもの
  - GNU で1プログラムのみでも、一般的な英語で、他の CLI でもよく使われるようなものは採用
- 次は除外：
  - ショートオプションがロングオプションのイニシャルでなく、わかりにくいもの

（※若干、恣意的になっていることは否めません。）

対応表:

short | long | GNU programs
:----:|:----:|-------------
a | all | du,ls,etc.
  | append | tee,time,etc.
  | archive | cp
  | ascii | diff
b | binary | cpio,diff
  | blocks | head,tail
c | bytes | head,split,tail
  | changes | chgrp,chown
  | command | su
C | copyright | ptx,recode,wdiff
d | date | touch
  | debug | make,m4
  | diff | tar
D | delete | tar
f | file | gawk,info,etc.
  | force | cp,ln,etc.
g | group | install
h | header | objdump,recode
i | include | etags
  | info | Finger
  | inode | ls
  | interactive | cp,ln,etc.
I | ignore | ls
j | jobs | make
k | kilobytes | du,ls
l | language | etags
  | link | cpio
  | list | recode
m | mail | hello,uname
  | mode | install,mkdir,mkfifo
n | dry-run | make
  | node | info
  | number | cat
o | options | getopt,fdlist,etc.
  | override | rm
  | owner | install
p | prompt | ed
P | port | finger
q | count | who
  | question | make
r | reference | touch
  | regex | tac,etags
  | release | uname
  | rename | cpio
  | reverse | ls,nm
s | shell | su
  | size | ls
  | strict | recode
  | strip | install
  | sum | gprof
  | symbolic | ln
S | stop | make
  | suffix | cp,ln,mv
t | tabs | expand,unexpand
  | touch | make,ranlib
  | trace | m4
T | terminal | tput,ul
u | update | cp,ctags,etc.
V | volume | tar
x | command | GDB
  | exit | xargs
  | extract | tar
z | gzip | tar,shar
  | uncompress | tar
Z | compress | tar,shar
0 | null | xargs


## その他、参考になるリソース

- [Standard Command-Line Options](http://www.tldp.org/LDP/abs/html/standard-options.html)
  - Linux Document Project 内の『Advanced Bash-Scripting Guide』の付録です。内容は、上の表に示したものに含まれていると言えます。

## 備考

やや古典的な資料、それも Unix ライクシステムに偏っているといえるかもしれません。
他のシステムなど、参考になる資料があれば、情報をいただけると嬉しいです。

# 終わりに

本稿が、コマンドラインツールを作る際の参考になれば幸いです。
誤りなどありましたら、お知らせ下さい。

# 本稿執筆にあたって他に参照した資料

- https://en.wikipedia.org/wiki/Command-line_interface
- [Commons CLI – Home](https://commons.apache.org/proper/commons-cli/index.html)
- [Utility Conventions](http://pubs.opengroup.org/onlinepubs/9699919799/basedefs/V1_chap12.html)
- [GNU Coding Standards: Command-Line Interfaces](https://www.gnu.org/prep/standards/html_node/Command_002dLine-Interfaces.html)

# 参考情報

- [Microsoft Command Line Standard](https://technet.microsoft.com/en-us/library/ee156811.aspx) ... Microsoft のコマンドラインツール開発規約

# 脚注