名前
getopt, getopt_long, getopt_long_only - コマンドラインオプションを解釈する
書式
#include <unistd.h>
int getopt(int argc, char * const argv[],
const char *optstring);
extern char *optarg;
extern int optind, opterr, optopt;
#define _GNU_SOURCE
#include <getopt.h>
int getopt_long(int argc, char * const argv[],
const char *optstring,
const struct option *longopts, int *longindex);
int getopt_long_only(int argc, char * const argv[],
const char *optstring,
const struct option *longopts, int *longindex);
説明
getopt() 関数はコマンドライン引き数を解釈する。 getopt() がとる引き数 argc と argv は、それぞれプログラムの起動時に main() 関数に渡された引き数の個数と配列である。 argv の要素のうち - で始まるもの (かつ "-" 単独や "--" 単独ではないもの) は オプション要素 (option element) とみなされる。 この要素から先頭の - を除いた文字は オプション文字 (option character) とされる。 getopt() は、繰り返し呼び出されるごとに、次のオプション文字を返す。
新たなオプション文字を見つけると、 getopt() はその文字を返し、 外部変数 optind とスタティックな変数 nextchar を更新する。 これらによって、 getopt() は次回の呼び出しの際に、 以降のオプション文字や argv 要素のスキャンを継続できる。
オプション文字がそれ以上見つからなくなると、 getopt() は -1 を返す。そして optind は、argv の要素のうち、 オプションでない最初の要素を示すようになる。
optstring は受け付けるオプション文字からなる文字列である。 文字のあとにコロン (:) が置かれている場合は、 オプションには引き数が必要であることを示す。 このとき getopt() は、現在注目している argv 要素で、オプション文字に引き続くテキストへのポインタか、 あるいは次の argv 要素のテキストへのポインタを optarg に代入する。 2 個連続してコロンが置かれている場合は、 そのオプションは引き数をとってもとらなくてもよい。 現在の argv 要素にテキストがあれば (つまり、"-oarg" のように、オプション名自身と同じワード内に テキストがある場合)、それが optarg に返される。 なければ optarg は 0 に設定される。 これは GNU による拡張である。 optstring に W とそれに続くセミコロンが入っていると、 -W foo は長いオプション --foo と同じように扱われる (POSIX.2 は -W オプションを実装依存の拡張として予約している)。 この動作は GNU による拡張であり、GNU libc 2 以前のライブラリでは 利用できない。
デフォルトでは getopt() は argv をスキャンする際に順序を変更し、 オプション以外の要素を最後に移動する。 他にも 2 つのモードが実装されている。 optstring の先頭文字が + であるか、環境変数 POSIXLY_CORRECT が設定されている場合には、オプションを対象とする動作は、 非オプションの引き数が現れた段階で終了する。 optstring の先頭文字が - である場合には、 オプションでない argv 要素は、 文字コード 1 のオプションであるかのように扱われる (これを用いるプログラムは、 オプションや argv 要素を任意の順序で受け入れ、かつそれらの順序が 意味を持つように書かれている必要がある)。 "--" は特殊な引き数で、スキャンのモードによらず、 オプションのスキャンを強制的に終了させる。
認識できないオプション文字があると、 getopt() はエラーメッセージを標準出力に表示し、 その文字を optopt に保存して ? を返す。 呼び出したプログラムで opterr を 0 にしておけば、 エラーメッセージの表示を抑制できる。
getopt() は argv の中に optstring にないオプション文字を見つけた場合、 またはオプション引き数が足りないことが分かった場合、 ? を返して外部変数 optopt をそのオプション文字に設定する。 optstring の (上で説明したオプションで指定できる + または - 後に続く) 最初の文字がコロン (:) のとき、 getopt() はオプション引き数が足りない場合に ? ではなく : を返す。 エラーを見つけた場合で、かつ optstring の最初の文字がコロンでなく、 かつ外部変数 opterr が 0 でない場合 (これがデフォルト)、 getopt() はエラーメッセージを表示する。
getopt_long() 関数は、長いオプション (2 つのダッシュ -- で始まるオプション) を 受け入れることを除いて getopt() と同じように動作する (プログラムに長いオプションだけが渡された場合、 optstring は NULL ではなく空文字列 ("") となる)。 長いオプションの名前は、他と重ならない範囲において短縮できる。 あるいは定義されたオプションに正確にマッチするものでも (当然) かまわない。 長いオプションは引き数を取ることができ、 --arg=param または --arg param と言う形式で指定する。
longopts は
struct option の要素からなる配列の、先頭要素へのポインタである。
struct option は
<getopt.h> で以下のように定義されている。
struct option {
const char *name;
int has_arg;
int *flag;
int val;
};
それぞれのフィールドの意味は以下の通り。
name | 長いオプションの名前。 |
has_arg | |
no_argument (または 0) なら、オプションは引き数をとらない。 required_argument (または 1) なら、オプションは引き数を必要とする。 optional_argument (または 2) なら、オプションは引き数をとっても とらなくても良い。 | |
flag | 長いオプションに対する結果の返し方を指定する。flag が NULL なら getopt_long() は val を返す (例えば呼び出し元のプログラムは、 val に等価なオプション文字を代入することができる)。 NULL 以外の場合には、 getopt_long() は 0 を返す。 このときオプションが見つかると flag がポイントする変数に val が代入される。見つからないとこの変数は変更されない。 |
val | 返り値、または flag がポイントする変数へロードされる値。 |
longindex は、NULL でなければ、 長いオプションのインデックスを longopts からの相対位置として保持している変数へのポインタとなる。
getopt_long_only() は getopt_long() と同様の動作をするが、 - も -- と同様に、長いオプションとして扱われる。- で始まる (-- 以外の) オプションが、長いものにはマッチしないが短いものに マッチする場合においては、それは短いオプションとして解釈される。
返り値
オプションが正常に見つかれば getopt() はそのオプション文字を返す。 すべてのコマンドラインオプションの解析が終わったら、 getopt() は -1 を返す。 optstring に含まれないオプション文字が見つかると、? を返す。 引き数が足りないオプションが見つかった場合、 返り値は optstring の最初の文字による異なる: 最初の文字が : であれば : を返し、 それ以外の場合は ? を返す。
getopt_long() と getopt_long_only() も、 短いオプション文字を認識した場合にはその文字を返す。 長いオプションに対しては、 flag が NULL なら val を返し、 flag が NULL 以外なら 0 を返す。 エラーと -1 の返り値は getopt() と同じである。 さらに ? は、マッチが確定できない場合や余分なパラメーターがある場合にも返る。
環境
POSIXLY_CORRECT | これが設定されていると、非オプションの引き数に到達した時点でオプション に対する操作が停止される。 |
_<PID>_GNU_nonoption_argv_flags_ | この変数は bash 2.0 が GNU libc と通信するために用いられた。 どの引き数がワイルドカードを展開した結果で、 したがってオプションとみなすべきでないかを知らせるものである。 この機能は bash のバージョン 2.01 で削除されたが、GNU libc にはまだ残っている。 |
準拠
getopt(): | |
環境変数 POSIXLY_CORRECT が設定されている場合は POSIX.2 と
POSIX.1-2001 に準拠する。
他の場合は argv の要素は本当の意味での定数にはならない。
なぜなら順序が変更されてしまうからである。
ただしそれらは、プロトタイプでは定数であるかのようにしてある。
これは他のシステムとの互換性のためである。
古い実装のいくつかでは、 getopt() は <stdio.h> で宣言されていた。 SUSv1 では、 <unistd.h> か <stdio.h> のどちらかで 宣言してもよかった。 POSIX.1-2001 では、 getopt の宣言を <stdio.h> で行うのは「過去の名残」であるとされた。 POSIX.1-2001 では <stdio.h> で宣言を行うことを認めていない。 | |
バグ
POSIX.2 における getopt() の仕様には技術的な問題があり、 その内容は POSIX.2 Interpretation 150 に記されている。 GNU による実装では (おそらく他のすべての実装でも)、 仕様と異なる正しい動作をするように実装されている。
例
以下に示す簡単なサンプルプログラムでは、
二種類のプログラムオプションを扱うのに
getopt() を使用している。一つは値を伴わない
-n で、もう一つは対応する値が必要な
-t val である。
#include <unistd.h>
#include <stdlib.h>
#include <stdio.h>
int
main(int argc, char *argv[])
{
int flags, opt;
int nsecs, tfnd;
nsecs = 0;
tfnd = 0;
flags = 0;
while ((opt = getopt(argc, argv, "nt:")) != -1) {
switch (opt) {
case n:
flags = 1;
break;
case t:
nsecs = atoi(optarg);
tfnd = 1;
break;
default: /* ? */
fprintf(stderr, "Usage: %s [-t nsecs] [-n] name\n",
argv[1]);
exit(EXIT_FAILURE);
}
}
printf("flags=%d; tfnd=%d; optind=%d\n", flags, tfnd, optind);
if (optind >= argc) {
fprintf(stderr, "Expected argument after options\n");
exit(EXIT_FAILURE);
}
printf("name argument = %s\n", argv[optind]);
/* Other code omitted */
exit(EXIT_SUCCESS);
}
以下は、
getopt_long() の使用法を、ほぼすべての機能について示したプログラムの例である。
#include <stdio.h> /* for printf */
#include <stdlib.h> /* for exit */
#include <getopt.h>
int
main(int argc, char **argv) {
int c;
int digit_optind = 0;
while (1) {
int this_option_optind = optind ? optind : 1;
int option_index = 0;
static struct option long_options[] = {
{"add", 1, 0, 0},
{"append", 0, 0, 0},
{"delete", 1, 0, 0},
{"verbose", 0, 0, 0},
{"create", 1, 0, c},
{"file", 1, 0, 0},
{0, 0, 0, 0}
};
c = getopt_long(argc, argv, "abc:d:012",
long_options, &option_index);
if (c == -1)
break;
switch (c) {
case 0:
printf("option %s", long_options[option_index].name);
if (optarg)
printf(" with arg %s", optarg);
printf("\n");
break;
case 0:
case 1:
case 2:
if (digit_optind != 0 && digit_optind != this_option_optind)
printf("digits occur in two different argv-elements.\n");
digit_optind = this_option_optind;
printf("option %c\n", c);
break;
case a:
printf("option a\n");
break;
case b:
printf("option b\n");
break;
case c:
printf("option c with value %s\n", optarg);
break;
case d:
printf("option d with value %s\n", optarg);
break;
case ?:
break;
default:
printf("?? getopt returned character code 0%o ??\n", c);
}
}
if (optind < argc) {
printf("non-option ARGV-elements: ");
while (optind < argc)
printf("%s ", argv[optind++]);
printf("\n");
}
exit(EXIT_SUCCESS);
}