getopt_long の振る舞い 1999年 5月 31日 第 1.0.3 版 笠原 基之 Copyright (c) 1998 Motoyuki Kasahara 概要 ==== GNU ソフトウェアに属するコマンドの多くは、UNIX では伝統的な `-c', `-l' のような一文字のコマンド行オプションに加えて、`--help', `--version' と いった長い名前のオプションが使用できるようになっています。GNU ソフトウェ アでは、getopt_long という C 言語の関数を用意し、この関数にコマンドラ インオプションの処理を行わせています。 この文書は、getopt_long がどのようにコマンド行オプションの解釈するのか について詳しく説明したものです。なぜこんな文書をわざわざ書いたのかと 言うと、簡単に見えて getopt_long は意外に複雑な処理をしているからです。 この文書を読むと、オプションにそんな指定方法があったのか、と思う方が いらっしゃるかも知れません。 ただしこの文書で説明しているのは、コマンド行引数を与えたときに getopt_long がどのように解釈するのかという事に限定しています。 getopt_long に関する C 言語プログラミングの上での仕様、たとえば関数の 引数や戻り値の意味といったことは、この文書では触れていません。 なお本書では、getopt_long の処理方式として PERMUTE という方式を使用し、 `optional argument' (引数を取っても取らなくても良いオプション) は使用 しないことを前提に書いています。これがもっとも一般的な処理方法だからと いうのがその理由ですが、これらを使用した場合の相違点については、本書の 末尾で少し説明しています (後述: 本書で扱わなかった getopt_long の機能 について)。 コマンド行引数の構成について ============================ シェル (sh, csh およびその互換のシェル) のコマンド行で以下のよう入力し たとします。 ls -l -R dirA dirB dirC 通常、シェルはこのコマンド行を次のように解釈されます。 コマンド名 ls 引数1 -l 引数2 -R 引数3 dirA 引数4 dirB 引数5 dirC (プログラミング言語によっては、コマンド名が引数列の先頭に来るように扱っ ていることもあります。また、引数列の要素が 1 でなく 0 から始まることも あります。しかし、これらのことは言語の仕様の違いによる差異に過ぎないの で、詳細については省きます。) getopt_long では、引数の処理は左から右の順番に行います。したがって、左 にある引数の方が「前」で、右にあるものが「後」になります。 (蛇足ですが、一般に UNIX 系 OS では、`*' 等のメタキャラクタの展開はシェ ルによって行われます。コマンドは、すでに展開された状態のものを受け取る ことになるので、コマンド側では展開処理について考慮する必要はありません。) 一文字オプション ================ 一文字オプション (single character option) は、UNIX 系システムのコマン ドで伝統的に仕様されている形式です。先頭のハイフン (`-') に続けて一文 字を添えたものが一文字オプションです。例えば `-l' や `-F' などは一文字 オプションです。 一文字オプションの名前 (`-' に続ける文字) に規定はありませんが、一般に 使用されるのは、英小文字、英大文字、数字です。英小文字と英大文字は区別 されます。`-' だけからなる引数は、一文字オプションではありません (後述: 「`-' の扱い」)。 一文字オプションの引数 ---------------------- 一文字オプションには、引数を取らないものと、引数を 1 つ取るものがあり ます。あるコマンド (getopt_long を使用した実行形式のプログラム) におい て、個々の一文字オプションが引数を取るか取らないかは、そのコマンドの仕 様で決まります。 あるコマンドにおいて、一文字オプション `-f' は引数を取ると仮定すると、 コマンドラインにおいて `-f' の引数を指定するには、 -f/etc/foo.conf のように、1 つのコマンド行引数の中で、一文字オプション名のすぐ後ろに続 けて書くか、あるいは -f /etc/foo.conf のように、一文字オプション、引数の順に 2 つのコマンド行引数に分けて書 きます。両者は意味的にまったく同じで、いずれも「一文字オプション `-f' の引数は /etc/foo.conf である」と言うことができます。 一文字オプション 1 つに対して 2 個以上の引数を持たせることは、どうやっ てもできません。 -f Hello World と書いても、`-f' の引数として解釈されるのは `Hello' だけです。 一文字オプションの引数の位置にあるコマンド行引数は、どのようなものでも (一文字オプションや長いオプションに見えるようなものでも)、オプション引 数と解釈されます。たとえば、 -f -f において、2 番目の `-f' は 1 番目の `-f' オプションの引数と解釈されま す。エラーにはなりません。 一文字オプションの連結 ---------------------- コマンド行において、同一の引数中に複数の一文字オプションを連結して指定 できます。たとえば、引数を取らない 3 つのオプション `-a', `-b', `-c' を -a -b -c と指定する代りに -abc と指定できます。もちろん、`-ab -c' や `-a -bc' といった指定も可能です。 いずれの表記も、まったく同じ意味を持ちます。一文字オプションを連結する 際は、末尾以外のオプションは引数を取らないオプションでなければなりませ ん。 末尾のオプションだけは、引数を取るオプションでも構いません。たとえば、 3 つのオプション `-a', `-b', `-c' のうち、`-c' だけが引数を取るとすれ ば、 -a -b -c zoo.jpg と指定する代りに -abczoo.jpg あるいは -abc zoo.jpg と指定することも可能です。 長いオプション ============== getopt_long では、一文字オプションに加えて、長いオプション (long option) が定義できます。 長いオプションは先頭を `--' で始めて、最低一文字以上の文字を続けます。 たとえば `--ignore-case' や `--version' は長いオプションです。`--' だ けからなる引数は、長いオプションではありません (後述: 「`--' の扱い」)。 オプションの名前 (`--' に続ける語句) に規定はありませんが、一般に使用 されるのは、英小文字、数字と `-' です。慣例で、英大文字は使いませんが、 使った場合は英小文字とは区別されます。 長いオプションの引数 -------------------- 一文字オプションと同様に、長いオプションにも、引数を取らないものと、引 数を 1 つ取るものがあります。あるコマンドにおいて、個々の一文字オプショ ンが引数を取るか取らないかは、そのコマンドの仕様で決まります。 コマンド行において長いオプションの引数を指定するには、 --file=/etc/foo.conf のように、1 つのコマンド行引数の中で、オプション名、`='、引数の順に続 けて書くか、あるいは --file /etc/foo.conf のように、長いオプション、引数の順に 2 つのコマンド行引数に分けて書き ます。なお、以下のように `=' の右側が空だった場合は、空文字列をオプショ ンの引数として与えることを意味します --file= 長いオプション 1 つに対して 2 個以上の引数を持たせるようにはできません。 長いオプションの引数の位置にあるコマンド行引数は、一文字オプションや長 いオプション、あるいは `--' のような体裁であっても、オプション引数と解 釈されます。たとえば、 --file --file=/etc/foo.conf において、2 番目の `--file=/etc/foo.conf' は 1 番目の `--file' オプショ ンの引数と解釈されます。 長いオプションの短縮 -------------------- 長いオプションは、他の長いオプションと区別が可能な範囲で、オプション名 の後方部分を省略することができます。たとえば、`--h' で始まる長いオプショ ンが `--help' だけならば、 --h --he --hel のいずれでも、`--help' という長いオプションとして認識されます。ただし、 `-', `--' というところまでは省略できません。 引数を取るオプションならば、省略形のまま引数を指定することも可能です。 たとえば正確には --debug-level=16 と書くところを、`--debug' で始まるオプションが他になければ --debug=16 --debug 16 と省略することも可能です。 ただし、どのオプションの短縮形なのか一意に決まらない場合は、エラーにな ります。`--help' と `--height' というオプションが定義されていた場合を 例にとると、 --hel --hei は、どちらの短縮形なのか区別がつきますが、 --h --he はどちらの短縮形とも取れるのでエラーになります。 また、あるオプションの指定が、あるオプションの完全な名前と、別のオプショ ンの短縮名の両方に一致する場合は、完全なオプション名を指定したものと解 釈されます。たとえば、`--file' と `--file-size' というオプションが定義 されていたとすると、コマンド行で --file と指定したときは、`--file' オプションを完全な名前で指定したものと解釈 され、エラーにはなりません。 非オプション引数 ================ コマンド行引数の中で、一文字オプション、長いオプション、およびオプショ ンの引数のいずれにも属さない引数は、非オプション引数 (non-option argument) として扱われます。 例として、GNU textutils に含まれている head コマンドをあげてみます。 head はファイルの先頭部分を取り出すためのコマンドです。head を使って `foo.txt' の先頭 10 行だけを取り出して標準出力に出力するには、次のよう にします。 head --lines 10 foo.txt ここで、`10' はオプション `--lines' の引数です。オプションは引数を一つ しか取れないので、`foo.txt' はオプション引数ではありません。したがって `foo.txt' は、非オプオプション引数ということになります。 あるコマンドが、何個の非オプション引数を指定できるかは、そのコマンドの 仕様によります。コマンドによっては、0 以上の任意個の非オプション引数を 取ることができるものもあれば、非オプション引数を一つも指定できないもの や、1個 や 2 個といった特定の個数分だけ指定しなければいけないものもあ ります。 先の head コマンドは、0 上の任意個の非オプション引数を取ることができま す。 head --lines=10 < foo.txt (標準入力から読む) head --lines=10 foo.txt (foo.txt から読む) head --lines=10 foo.txt bar.txt (それぞれのファイルから読む) 非オプション引数を置ける場所 ----------------------------- 非オプション引数のおける場所は、コマンド実行時に環境変数 POSIXLY_CORRECT が定義されているかどうかで、異なってきます。 環境変数 POSIXLY_CORRECT が定義されていない場合、コマンド名の前や、オ プションの引数として解釈される場所でなければ、非オプション引数はどこに 置いても構いません。getopt_long の内部処理によって、非オプション引数は コマンド行引数の末尾に移動されます。したがって、GNU testutils の tail コマンドでは、次の 2 つの行は等価になります。 tail foo.txt --lines=10 -q bar.txt tail --lines=10 -q foo.txt bar.txt ただし、オプションの指定順序や、非オプション引数の間の指定順序は保って いることに注意して下さい。これまで変えてしまうと、等価ではなくなってし まいます。 環境変数 POSIXLY_CORRECT が定義されている状態でコマンドが起動された場 合、非オプション引数は、オプション群の後ろに置かないといけません。最初 の非オプション引数が現われた時点で、オプションの識別処理は終了します。 つまり、以降の引数の中に、たとえ `-a' や `--help' といったものが含まれ ていても、オプションとして認識されません。ですから、先ほどの例では、 tail --lines=10 -q foo.txt bar.txt という書き方であれば、環境変数 POSIXLY_CORRECT が定義されていてもいな くても、解釈は変わりませんが、 tail foo.txt --lines=10 -q bar.txt という書き方では、POSIXLY_CORRECT が定義されていると、非オプション引数 `foo.txt' が出現した時点で、以降のオプションの解析は行いません。したがっ て「オプションは一つも指定されておらず、`foo.txt', `--lines=10', `-q', `bar.txt' という 4 つの非オプション引数が指定されている」と解釈されて しまいます。 `-' と `--' =========== 引数に `-' や `--' が与えられた時の処理方法について記します。 `-' の扱い ----------- 一文字だけからなる引数 `-' は、オプションとしては認識されず、特別な意 味もありません。`-' という値の 1 個のコマンド行引数として扱われます。 `--' の扱い ----------- 二文字だけからなる引数 `--' は、長いオプションとしては認識されません。 しかしながら、`--' は特別な意味を持ち、環境変数 POSIXLY_CORRECT の定義 の有無にかかわらず、オプションの識別処理をそこで強制的に終了させる働き があります。つまり、`--' 以降の引数は、たとえ `-a' や `--help' といっ たものであってもオプションとして認識されず、すべて非オプション引数であ ると解釈されます。 ただし、オプションの引数の位置に `--' が置かれた場合は、この機能は働き ません。たんにオプションの引数として普通に解釈されます。また、2 度目以 降に現われた `--' は単なる非オプション引数として解釈されます。たとえば GNU fileutils の ls コマンドで、`--' というファイルについて調べるには ls -l -- -- とすれば良いことになります。 エラーメッセージ ================ ユーザが getopt_long を使用しているコマンドを起動した際に、getopt_long が出力し得るエラーメッセージは、次の通りです。エラーメッセージは標準エ ラー出力に出力されます。 <コマンド名>: option `<指定された長いオプション名>' is ambigous 指定された長いオプションの省略形から、オプションの完全な名前が 一意に決まらない。 <コマンド名>: unrecognized option `<指定された長いオプション名>' そのコマンドで定義されていない長いオプションが指定された。 <コマンド名>: option `<指定された長いオプション名>' requires an argument 引数を取る長いオプションを、引数なしで指定した。 <コマンド名>: option `<完全な長いオプション名>' doesn't allow an argument 引数を取らない長いオプション名を引数付きで指定した。(このエラー が出力されるのは、`=' の後ろに引数を指定する方法を用いた場合だ けである。) <コマンド名>: illegal option -- <一文字オプション名> そのコマンドで定義されていない一文字オプションが指定され、かつ 環境変数 POSIXLY_CORRECT が定義されている。 <コマンド名>: invalid option -- <一文字オプション名> そのコマンドで定義されていない一文字オプションが指定され、かつ 環境変数 POSIXLY_CORRECT が定義されていない。 上記の中で使われている記号の意味を、補足します。 <コマンド名> コマンド行で指定された、コマンド名。コマンド行で指定された通り の文字列がそのまま用いられるので、コマンド名にパスを含むかどう かは、実際にコマンド行でパスが指定されたかどうかによる。 <指定された長いオプション名> 先頭の `--' を含む、長いオプション名。ただし、オプションの引数 は除く。コマンド行で指定された通りの文字列を用いるので、省略形 の場合も完全な名前に変換することはしない。 <完全な長いオプション名> 先頭の `--' を含む、長いオプション名。ただし、オプションの引数 は除く。省略形の場合は、完全な名前に変換したものを用いる。 <一文字オプション名> 一文字オプション名から、先頭の `-' およびオプションの引数を除 いたもの。 環境変数 POSIXLY_CORRECT ======================== 既に述べた通り、ユーザが getopt_long を使用しているコマンドを起動した 際、環境変数 POSIXLY_CORRECT を定義しているかどうかで、オプションの処 理に次のような影響を与えます。 1. 非オプション引数が現われた時点で、オプションの識別処理は終了す る。 2. そのコマンドで定義されていない一文字オプションが指定されたとき、 エラーメッセージ `invalid option' が `illegal option' に変わる。 (これは、`illegal' という語が「違法の」という意味を持っている ことから GNU project では使用しないようにしている一方で、POSIX ではこの `illegal ...' というメッセージを仕様として規定してい るためである。詳しくは GNU Coding Standards の `GNU Manuals' の節を参照のこと。) 付録: 本書で扱わなかった getopt_long の機能について =================================================== PERMUTE 以外の処理方式 ---------------------- getopt_long には、本書で前提としている PERMUTE という処理方式以外に、 REQUIRE_ORDER, RETURN_IN_ORDER という方式があります。どの処理方法が使 われるかは getopt_long を使用しているアプリケーションプログラムがどの 処理方式を選択するかによります。 REQUIRE_ORDER は、最初の非オプション引数が現われた時点で、オプションの 識別処理は終了する処理方式です。PERMUTE でも環境変数 POSIXLY_CORRECT が定義されていた場合は、これと同じ処理方式になります (参照:非オプショ ン引数を置ける場所)。 RETURN_IN_ORDER は基本的に PERMUTE と同じですが、オプションと非オプショ ン引数の順番を保持します。(PERMUTE では、非オプション引数はコマンド行 の引数列の末尾に寄せられます)。たとえば、あるコマンドで「aaa.xpm の色 は blue, bbb.xpm の色は red」というような指定を行う場合、処理方式に RETURN_IN_ORDER を採用すれば、次のような書式で実現できるようにすること もできます。 --color=blue aaa.xpm --color=red bbb.xpm このように、指定順序によって振る舞いが変わるような仕様がそのコマンドに 含まれない場合は、RETURN_IN_ORDER と PERMUTE には違いは無いと言って良い でしょう。 optional argument ----------------- 本書でこれまで解説したように、オプションには引数を取る `required-argument' タイプのオプションと、引数を取らない `no-argument' タイプのオプション がとありますが、長いオプションに限り、オプションの引数を取っても取らな くても良い `optional-argument' タイプのオプションというものも存在しま す。 getopt_long_only ---------------- getopt_long とよく似ていますが、getopt_long_only という関数が用意され ています。getopt_long と違うのは、長いオプションの先頭は `-' でも `--' でも良い、という点です。`-' で始まる引数が長いオプション名に適合しない ときは、一文字オプションとして解釈されます。