getopt - みる会図書館


検索対象: UNIX MAGAZINE 1991年5月号
5件見つかりました。

1. UNIX MAGAZINE 1991年5月号

します。それ以外の場合には、オプションとして認識した 文字を返します。つまり、変数 c にはオプションとして認 識した文字が入れられます。ループ本体では、このオプシ ョンとして認識された文字に応して処理をおこなっていま す。 a や b がオプションとして検出されれば、それぞれのオ プションを示す変数の値を 1 増やしています。もともとこ れらの値は 0 だったので、 C 言語においては偽として処理 されるはすです。しかし、値が 1 増やされて 1 となったの で、真と判断されるようになります。オプションとして c が 訒識されたらオプションのための引数もついているはすで 川じ、 すから、その値を optarg から c ー file にコピーしておきま す。最後に、それぞれのオプションの内容を示す変数にし たがってオプションの値を出力し、 c オプションが設定さ れている場合には対応する引数のファイル名も出力して います。ここに示したプログラムは、あくまで一例にすぎ ません。コマンドに対するオプションはそれぞれ異なりま すから、必要なものを適宜指定するようにしてください。 また、 getopt ライプラリ関数が EOF を返したときに は、まだ解析していない部分にオプション以外のコマンド に対する引数が残っているはすです。これらの引数に対す る処理をおこないたいときには、。 ptind 変数を使用してく ださい。 optind 変数の値は、次に getopt ライプラリ関数 が処理すべき引数を示しています。つまり、、、 argv Coptind]" はまだ処理されていない最初の引数となりま す。 optind が argc よりも小さいあいだ、つまり、 opt ind + + ) { for ( ; optxnd く argc argv Coptind] とすれは、 getopt ライプラリ関数によって処理されなかっ た引数に対する処理がおこなえます。 get 叩 t ライプラリを使った getopt コマンド こで、 get 叩 t ライプラリを理解するために、この関数 を用いて getopt コマンドを書いてみましよう。 getopt コ マンドがどのように作成されているかは分かりませんが、 getopt コマンドと getopt ライプラリ関数について調べ てみると、どうやら get 叩 t ライプラリ関数を使えは簡単 に書けそうです。 UNIX MAGAZINE 1991.5 IJN Ⅸ流プログラミング 7 解析できないオプションが指定された場合に出力され るメッセージは、どちらもよく似ています。 getopt コマン ドに与える第 1 引数を getopt ライプラリ関数への第 3 引 数とすれば、オプションの解析ができるようになります。 それでは、第 1 引数と第 2 引数には何を渡したらいいので しようか。 通常はコマンドに与えられた引数を示す argc と argv を渡すのですが、さきほどのような場合はこのまま与えた のではよぶんな引数も渡ってしまいます。正しくは、コマ ンドに対する第 1 引数をスキップしたものを渡さなければ なりません。 もう 1 つの間題は、引数をとるようなオプション ( 、、・ っきのオプション指定 ) が与えられた場合、そのオプション に引数がっくのかどうかをどうやって見分けるかという点 です。本来なら、第 1 引数を見て getopt ライプラリ関数に よって返された文字をそのなかから捜し、その次の文字が 、、 : 〃ならは引数があると判断するのでしようが、さいわい なことにオプションに対する引数がない場合には、外部変 数の optarg が NULL になっているようです。今回は、 の特性を利用してプログラムを書いてみました 4 。 せつかくですから、引数として不適切なものが与・えられ たり、必要な引数が与えられなかった場合の動作も get 叩 t コマンドに揃えてみましよう。意地悪な引数をえ ると、 get 叩 t コマンドは次のように動作します。 % getopt usage : getopt legal-args $ * % getopt ab -abcd 〉 getopt : illegal option getopt : illegal option % getopt ab: % getopt ab: abc abc 必要な引数ーーーっまり、オプション文字を指定する引数 が指定されなかった場合、 getopt コマンドは、、 usage:" を 出力します。これについては機会をあらためて説明する予 定ですが、コマンドの使い方を標準工ラー出力に出力する ものです。また、認識できないオプションがあると、その オプションを標準工ラー出力に出力し、コマンド自身の出 4 ひょっとすると、 こうはならない getopt ライプラリが存在するかもしれませ ん。そのような場合には、 考えられます。 こで挙けるプログラムが適正に動作しないことも 139

2. UNIX MAGAZINE 1991年5月号

ミング 7 図 3 : argc と argv 3 ) argc 1 argv NULL a b 0 \ 0 \ 0 u 0 と t LJN Ⅸ流プログラ \ 0 次に while に戻ったときには argc が 0 となって、 の比較で偽となりますから、このループを終了することに なります。お分かりいただけたでしようか。 まとめて指定するオプション ようにすると、コードは次のようになります。 前例の a 、 b 、 c というオプションをまとめて指定できる 引数のそれぞれの文字を検査するコードが必要です。 この場合には、さきほどのような引数ごとのループに加え、 には、どのようなプログラムにすれは・よいのでしようか。 字のオフションをいくつかまとめて指定できるようにする れぞれを独立して指定しなければなりませんでした。 1 文 これまで扱ってきた方法では、ユーサーがオプションそ 1 while (—-argc > の { 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 } while ( * + + p ) { swi tch case break ; flag-a + + ; bre ak ; flag-b + + ; break ; flag-c + + , bre ; すべてのオプションが 1 文字の場合には、ここで示した ようにループを二重にすれば対処できます。ここでは p と いう変数を新たに用いています。この変数は文字へのポイ UNIX MAGAZINE 1991.5 ンタ型で、引数のそれぞれの文字を対象に処理をおこなう ために内側のループで使用されています。 p は、内側のルー プに入るときにそれぞれの引数の先頭文字 ( ー ) を指すよ うに設定されます。そして、 while の比較の段階で次の文 字 ( オプションの最初の文字 ) を指すように変更され、内側 のループを回ります。それぞれの引数の末尾には文字列の 終りを示す、、 \ 0 〃がついていますから、その値を検出した ら内側のループを終了するようになっています。 こでは、実際に引数が与えられたときにどのように動 作するかはあえて述べません。自分がコンピュータになっ たつもりでどのような動作をするか考えてみると、どうい うふうにプログラムを書けばよいのかが分かってくるでし 137 引数の先頭を示します。これらの変数 ( とくに optind) の るオプションを検出した場合にそのオプションに対応する る引数に対応する argv の添字を示し、 optarg は引数をと の変数を外部変数として利用します。 ophnd は次に処理す optarg という char * 型の変数と optind という int 型 getopt ライプラリ関数は、これらの引数のはかにも ロン ( : ) をつけます。 また、引数をとるオプションの場合には、文字の後ろにコ 様にオプションとして認識する文字の並びを指定します。 string です。 optstring に対しては、 getopt コマンドと同 argv 、そして getopt コマンドの第 1 引数に対応する opt- る引数は、 main 関数に与・えられるものと同し gc と ドとほとんど同し機能をもっています。 getopt 関数に対す ています。この getopt ライプラリ関数は、 getopt コマン えませんが、かわりに getopt ライプラリ関数が用意され C 言語でのオプションの解釈には getopt コマンドは使 getopt ライプラリ

3. UNIX MAGAZINE 1991年5月号

、、まり、 getopt ライプラリ関数の戻り値が EOF だったらオ 値を勝手に変更した場合の動作は保証されていませんか プションの処理が終り、あとに残っているのは実際の引数 十分に注意してください。 と考えれはいいわけです。このあたりの動作は getopt コ これらの値は外部変数として宣言されているので、最初 マンドとよく似ていますね。 の呼出しの際には 0 に初期化されています。オプションと get 叩 t ライプラリ関数を利用して、 B シェルや C シェル して認識できない文字を見つけたら、 get 叩 t ライプラリ関 のときと同し機能を備えたオプションを解析するプログ 数は EOF を返します。また、特別な引数、、一一〃を見つけた ときにもオプションの解析を終了し、 EOF を返します。っ ラムを書くと、次のようになります。 % cat option—test. c #include く stdio . h> main(argc , argv) int argc ; char * * argv ; int a-flag = 0 , b-flag = 0 , c-flag = 0 , err-flag = 0 ; char *c_file = NULL; Int C ; extern int optind ; extern char *optarg : while ( (c = getopt (argc , 矼空 , 'abc : switch (c) { case a—flag + + : break ; b—f lag + + : break ; c-flag + + : c—file = optarg; bre ak ; label; goto case ) C ) default : ・ 1 1 亠一 1 1 亠 1 工 1 十亠 ・ 1 りん″んりん Ⅱれ q-H 0 0 0 「 1 1 工 A-. A 人・ 1 、ト - label: このプログラムをもうすこし詳しく見てみましよう。 このプログラムはオプションに a 、 b 、 c をとり、 c とい 最初に、 optind と optarg を外部変数として宣言してい うオプションが引数をとることを getopt ライプラリ関数 ます。これらの変数を宣言しておかないと、あとで利用で の引数として指定しています。これだけでは分かりません きなくなるので注意してください。さて、実際の引数処理 が、 getopt ライプラリ関数は画面に出力をする数少ないラ イプラリの 1 つです。 optstr ⅲ g にないオプションを検出 は while ループでおこなわれています。このループを回る すると、、”を返し、メッセージを標準ェラー出力に出力 条件は、 getopt コマンドが返した値が EOF ではないこと です。 getopt コマンドは、認識できないオプションを見つ します。このときにはコマンド名も出力されますが、これ けるか、引数がすべて終了してしまったときに EOF を返 は argv から取り出されます。 138 UNIX MAGAZINE 1991.5

4. UNIX MAGAZINE 1991年5月号

力はおこないません。これらの点を考慮すると、次のよう なプログラムになります。 % cat getopt ・ c while ( (c = getopt (argc , argv , opt-str) ) ! = EOF) { printf ("%s 髫矼空 [optind] ) ; main(argc , arg の #include く stdio . h> int argc ; char int char 1 れ t char char ext ern ext ern *opt—str; err = 0 ; arg CBUFSIZ] ; buf [BUFSIZ] ; optind ; int char *opt arg ; if (argc fprintf (stderr , exit(l); opt-str = 矼空 [ 1 ] ; 矼空 [ 1 ] = 矼空 [ 0 ] ; argv 十十 ; -argc ; buf [ 0 ] if (c err 十十 ; usage : getopt legal-args $*\n") ; cont lnue ; sprintf (arg , "-%c ー strcat (buf , arg) ; if (optarg) { sprintf (arg, "%s strcat (buf , arg) ; , optarg) ; if (err) { exit(l) ; printf ("%s- , buf) ; for ( ; optind く argc putchar( ' \ ) ; exit ( の ; opt i れ d + + ) { このプログラムでは、各種変数の宣言をおこなってから 引数の数を調べています。 argc の値が 1 、つまりコマンド 名以外の引数が何も・与えられなかったときは、 getopt コ マンドと同様に、、必要な引数が与えられなかった′′と表示 し、実行を終了します。認識できないオプションが与えら れた場合の処理が書かれていないように見えますが、これ は get 。 pt ライプラリ内で処理されます。そのようなケー スでは、オプション文字として〃が返されます。この 140 プログラムでは、、、 ? 〃が返された場合には err 変数を 1 増 やし、引数のなかにエラーがあったことを示しています。 実際に解釈したオプションを出力するには、 get 叩 t ライ プラリが返した文字や optarg が指し示している文字列を そのまま出力してもよいのですが、エラーがあると不要な 出力がおこなわれることになります。そこで、このプログ ラムではいったん文字配列に格納しておき、エラーのない ことが判明してから出力するようにしています。 UNIX MAGAZINE 1991.5

5. UNIX MAGAZINE 1991年5月号

getopt ライプラリ関数による処理が終ったら、エラー が存在したかどうかを検査し、エラーがあったら実行を終 了します。工ラーがなかったら、それ以降は普通の引数で あることを示す、、一ノを出力し、残りの引数も出力してい ます。 getopt コマンドがないために、前回にお話しした B シェ ルでのオプションの解釈が実験できなかったという人は、 このプログラムをコンパイルして試してみてください。 単語で指定するオプション こまでは 1 文字のオプションでしたが、単語で指定す るオプションのときはどうするのでしようか。この場合に while (-—argc > 0 ) { if (strcmp(*argv , "-help't) IJN Ⅸ流プログラミング 7 、、・は、 get 叩 t は使えません。また、複数のオプションをまと めて指定することもできません。そこで、冒頭で挙げた例 を思い出してください。 最初の例では [ 1 ] 〃、つまりそれぞれの引数の 2 文字目を switch での分岐に用いてさまざまなオプショ ンを解析していました。 switch で分岐ができるのは int 型のものだけですから、単語をオプションとして指定する ときには利用できません 5 。 1 つ考えられるのは、 switch-case を利用するのではな く、 if-then-else を組み合わせて判断する方法です。この 方法を使うと、たとえば、、 -help" と、、 -large" というオプ ションをとるプログラムは、次のように書くことができま す。 } else if (strcmp(*argv , } else { fprintf (stderr , break ; } else { 1 矼 ge " ) ' un iown option %s\n" , *argv) ; = の { これを必要なオフションの数だけつくれはよいのです。 ほかにもいろいろな方法が考えられます。たとえば、オ プションとして認識できる単語をテープルとしてもってい て、そのテープルに対するインデックスを返すような関数 を書けば、そのインデックスの値を利用して switch-case 形式で書くこともできます。 変わったところでは、 getopt ライプラリを使っても実現 できます。各オプションの先頭 1 文字を、引数をとるオプシ ョンとして認識させ、 2 文字目以降を optarg の値を用い て比較し、実際に指定されているオプションを判断すれば よいのです。また、 UNIX の世界で普及している X ウイン ドウ・システム関連のプログラムを作成するときには、ツ ールキットという手法を使えば、より簡単に単語としての オプションが解析できます。これについては、機会があれ ばいすれお話ししたいと思います。 今回は、 C 言語によるオプションの解釈方法について説 明しました。オプション文字を解析する方法は、はかにも UNIX MAGAZINE 1991.5 多種多様に考えられます。ソースプログラムを入手できる フログラムがあれは、それらのオプションの扱い方を見て 研究してもいいでしよう。 次回は、コマンドに対する引数が期待したものと異なっ ているときに出力される、、 usage 出力クについてお話しす る予定です。 ( いまいすみ・たかし東京工業大学 ) 5 cha 「型は int 型に変換できるので、 switch で利用できます。 141