getoptsでロングオプションを使う


映画『氷菓』(2017)

見はじめたのはアニメの方なんですが、まだ2話なので、先に映画の方見た方がよいかなあと、迷ってます。映画のPV見てしまうと、どうしても見ないと気が済まなくなってしまいます。

getoptではショートオプション、ロングオプションを使ってみたので、getoptsでも、ロングオプションを使ってみたいと思います。
しかし、man bashを見ても、ロングオプションのことが書いてありません。仕方ないので、bashのソースコードを読んでみます。
まずは取得。

takk@deb9:~$ mkdir src
takk@deb9:~$ cd src
takk@deb9:~/src$ apt-get source bash

バージョンは、4.4です。

takk@deb9:~/src$ ls
bash-4.4  bash_4.4-5.debian.tar.xz  bash_4.4-5.dsc  bash_4.4.orig.tar.xz
takk@deb9:~/src$ cd bash-4.4
takk@deb9:~/src/bash-4.4$ 

さっそくgrep。大量に出るのでファイル一覧を眺めます。

takk@deb9:~/src/bash-4.4$ grep -rl getopts *
AUTHORS
CHANGES
CWRU/changelog
ChangeLog
MANIFEST
Makefile.in
builtins/Makefile.in
builtins/getopt.c

~省略~

tests/getopts10.sub
tests/getopts.right
tests/nameref.right
variables.c
takk@deb9:~/src/bash-4.4$

本当に大量に出てきたので間引きましょう。poやdocといったディレクトリは処理が入っていないはずなので、検索から除外します。

takk@deb9:~/src/bash-4.4$ grep -rl getopts * --exclude-dir={po,doc,tests,examples}
AUTHORS
CHANGES
CWRU/changelog
ChangeLog
MANIFEST
Makefile.in
builtins/Makefile.in
builtins/getopt.c
builtins/common.h
builtins/mkbuiltins.c
builtins/getopts.def
debian/changelog
debian/bash-builtins.7
execute_cmd.c
support/mkclone
support/rlvers.sh
variables.c
takk@deb9:~/src/bash-4.4$ 

ヒットするファイル数が少なくなったところで、文字列のファイル内を検索。

takk@deb9:~/src/bash-4.4$ ^-rl^-r^
grep -r getopts * --exclude-dir={po,doc,tests,examples}
AUTHORS:builtins/getopts.def	Brian Fox, Chet Ramey
CHANGES:eee. Bash now restores getopts' internal state between calls to getopts even if
CHANGES:g.  Fixed a bug that caused the getopts builtin to not return failure if an

~省略~

builtins/getopts.def:dogetopts (argc, argv)
builtins/getopts.def:  /* argv[0] is "getopts". */
builtins/getopts.def:      getopts_unbind_variable ("OPTARG");
builtins/getopts.def:      getopts_bind_variable (name, "?");
builtins/getopts.def:      ret = getopts_bind_variable (name, "?");
builtins/getopts.def:	getopts_unbind_variable ("OPTARG");
builtins/getopts.def:	  ret = getopts_bind_variable (name, ":");
builtins/getopts.def:	  ret = getopts_bind_variable (name, "?");
builtins/getopts.def:	  getopts_unbind_variable ("OPTARG");
builtins/getopts.def:  return (getopts_bind_variable (name, strval));
builtins/getopts.def:/* The getopts builtin.  Build an argv, and call dogetopts with it. */
builtins/getopts.def:getopts_builtin (list)

~省略~

takk@deb9:~/src/bash-4.4$ 

どうやらgetopts.defというファイルで、getoptsの処理を実施しているようです。しかし、このgetopts.defにロングオプションの処理が見つかりません。ということは、getoptsではロングオプションは使えないということになってしまいます。そう判断する前にちょっと気になることが。ファイルの拡張子がdefってこともあり、getoptsを使った時に、本当にこのgetopts.defの処理が走るのか、少々自信がありません。printfを追加して確認してみます。
175行目にHELLO表示を追加しました。

takk@deb9:~/src/bash-4.4$ cat -n builtins/getopts.def

~省略~

   162  static int
   163  dogetopts (argc, argv)
   164       int argc;
   165       char **argv;
   166  {
   167    int ret, special_error, old_opterr, i, n;
   168    char strval[2], numval[16];
   169    char *optstr;                 /* list of options */
   170    char *name;                   /* variable to get flag val */
   171    char *t;
   172
   173    if (argc < 3)
   174      {
   175        printf("HELLO\n");
   176        builtin_usage ();
   177        return (EX_USAGE);
   178      }

~省略~

printfを追加したらビルド。

takk@deb9:~/src/bash-4.4$ ./configure
takk@deb9:~/src/bash-4.4$ make
takk@deb9:~/src/bash-4.4$ ./bash

実行します。getoptsに適当に引数を与えます。

takk@deb9:~/src/bash-4.4$ getopts a
HELLO
getopts: usage: getopts optstring name [arg]
takk@deb9:~/src/bash-4.4$ 

HELLOが表示されたので、getopts.defの処理が実行される、ということで間違いないようです。やはりロングオプションの処理はしてないってことですね。

さて、どうしたものか。
ロングオプションは、–から始まることを利用して、ショートオプション名が”-“である、という解釈で解析しても良いかもしれません。その場合は、値付きのオプションとするため、:(コロン)が必要になります。
例えばこんなスクリプトにします。

takk@deb9:~$ cat -n test.sh
     1	#!/bin/bash
     2	
     3	while getopts "abcde-:" ret $@
     4	do
     5	  echo -e $ret $OPTARG
     6	done
     7	
takk@deb9:~$ 

実行すると、

takk@deb9:~$ ./test.sh -abcde --this_is_longoption
a
b
c
d
e
- this_is_longoption
takk@deb9:~$ 

オプション”-“の値として、this_is_longoptionが取得できました。
ヘビーな使い方をしないのであれば、これで十分かも。

Leave a Reply

Your email address will not be published. Required fields are marked *

CAPTCHA