perlスクリプトの引数処理モジュール`Getopt::Kingpin`の紹介

  • 17
    いいね
  • 0
    コメント

perlで引数処理といえばGetopt::Longがコアモジュールなのもあり、よく使われています。
このページでは、引数処理の新しい選択肢として拙作のGetopt::Kingpinを紹介します。

Goal

  • Getopt::Kingpinを知ってもらう
  • Getopt::Kingpinを使ってスクリプトが書けるようになる

Getopt::Kingpinを作った理由

職場ではperlとgolangの両方でスクリプト/ツールを作成しています。

perlだとGetopt::Long、golangではkingpinを使ってコマンドライン引数等の処理をしていました。
が、徐々にGetopt::Longだと(kingpin比で)気持ちよくなくなってきてperlでツールを書くのが億劫になってくるという状況。

ということで、「kingpinをperlに移植したら気持ちが楽になるんじゃ?」という心が芽生えて作成に至りました。

golangで書かれた本家kingpinの良い所

雑に書くと以下が良い所です。

  • シンプルで覚えることが少ない
  • flagとargを同じ形で扱える
  • サブコマンド対応
  • helpの自動生成

詳しくは、オフィシャルおよび以下の記事を読んでください。

インストール

cpanm Getopt::Kingpinでインストール可能です。
perl 5.8.1以降で動作します。

使い方

例えば、

  • --verboseもしくは-vというboolのflagを持つ
  • 引数name必須

というスクリプトは以下のように書けます。

use Getopt::Kingpin;
my $kingpin = Getopt::Kingpin->new;

my $verbose = $kingpin->flag('verbose', 'Verbose mode.')->short('v')->bool;
my $name    = $kingpin->arg('name', 'Name of user.')->required->string;

$kingpin->parse;

# perl sample.pl hello
printf "name : %s\n", $name;

この時点で、--helpも実装されているためヘルプを表示することが可能です。

usage: sample.pl [<flags>] <name>

Flags:
      --help     Show context-sensitive help.
  -v, --verbose  Verbose mode.

Args:
  <name>  Name of user.

とても簡単です。

使い方(その2)

gitのようにサブコマンドを持つスクリプトも簡単に作成することができます。

use Getopt::Kingpin;
my $kingpin = Getopt::Kingpin->new("chat.pl", "A command-line chat application.");

my $register      = $kingpin->command('register', 'Register a new user.');
my $register_nick = $register->arg('nick', 'Nickname for user.')->required->string;
my $register_name = $register->arg('name', 'Name for user.')->required->string;

my $post         = $kingpin->command('post', 'Post a message to a channel.');
my $post_image   = $post->flag('image', 'Image to post.')->file;
my $post_channel = $post->arg('channel', 'Channel to post to.')->required->string;
my $post_text    = $post->arg('text', 'Text to post.')->string_list;

my $cmd = $kingpin->parse;

if ($cmd eq 'register') {
    printf "register %s %s\n", $register_nick, $register_name;
} elsif ($cmd eq 'post') {
    printf "post %s %s %s\n", $post_image, $post_channel, @{$post_text->value};
} else {
    $kingpin->help;
}

perl chat.pl --helpで表示されるヘルプは以下のようになります。

usage: chat.pl [<flags>] <command> [<args> ...]

A command-line chat application.

Flags:
  --help  Show context-sensitive help.

Commands:
  help [<command>...]
    Show help.

  register <nick> <name>
    Register a new user.

  post [<flags>] <channel> [<text>...]
    Post a message to a channel.

perl chat.pl --help postのようにサブコマンド単位のヘルプも可能です。

usage: chat.pl post [<flags>] <channel> [<text>...]

Post a message to a channel.

Flags:
  --help         Show context-sensitive help.
  --image=IMAGE  Image to post.

Args:
  <channel>  Channel to post to.
  [<text>]   Text to post.

Getopt::Kingpinの基本

最小のプログラム

最小のプログラムは以下になります。
必ず$kingpin->parse()する必要があることに注意。
この時点で最低限のヘルプは実装できています。
parse()は引数無しだと@ARGVを使って処理する形となっています。

use Getopt::Kingpin;
my $kingpin = Getopt::Kingpin->new;
$kingpin->parse;

flagを受け取る

flagには--verboseのようなlong flagと、-vのようなshort flagがあります。
定義するには以下のように書きます。

my $verbose = $kingpin->flag('verbose', 'Verbose mode.');

このままでもいいのですが、セットされたかどうかを表すbool値として処理したい場合は、bool()を付けて呼び出します。
bool型については、--verbose(true)と--no-verbose(false)に対応しています。
単にflag()を定義するとstringとして処理されるため文字列なら何でもOKという状態になります。

my $verbose = $kingpin->flag('verbose', 'Verbose mode.')->bool;

short flagを定義する場合は、以下のようにします。

my $verbose = $kingpin->flag('verbose', 'Verbose mode.')->short('v')->bool;

デフォルト値を1とするには、以下のようにします。

my $verbose = $kingpin->flag('verbose', 'Verbose mode.')->short('v')->default(1)->bool;

$kingpin->parseをした後は、$verbose->valueとすることで、0 or 1の値を取り出すことができます。
が、ほとんどのケースにおいてはprint "xxx" if $verboseのように書いても正しく動作します。

いろいろな型

Getopt::Kingpinの0.06時点では以下の型を使うことができます。
型を指定しない場合はstringになりますし、stringはなんでも受け取り可能のため、困ったらstringという形で使うとよいです。

  • string()
  • bool()
  • existing_dir()
  • existing_file()
  • existing_file_or_dir()
  • file()
  • int()

existing_dir()existing_file()existing_file_or_dir()は存在確認をしつつPath::Tinyオブジェクトを返します。
file()は存在確認はしませんがPath::Tinyオブジェクトを返します。

スクリプトでは、file/directoryを扱うことが多いためこれらをうまく使うと楽に書けます。

my $file = $kingpin->flag("file", "file to output")->existing_file;
$kingpin->parse;

printf "%s\n", $file;                  # 引数で入力した文字列が取り出せる
printf "%s\n", $file->value->absolute; # Path::Tinyのabsoluteを使う
printf "%s\n", $file->absolute;        # このようには書けないので注意

argを受け取る

基本的にはflagと同じです。
argは、典型的には--とか-がついてない引数のことで順番/位置が重要となります。

my $name    = $kingpin->arg('name', 'Name of user.');

nameという引数を必須にするには以下のようにします。

my $name    = $kingpin->arg('name', 'Name of user.')->required;

flagとargまとめ

$kingpin->flagもしくは$kingpin->argの後に続けて書ける記述をまとめます。
色々書いてますが、使用例等はpodを確認してください。

名前 備考
short() short flagを設定する
default() デフォルト値を設定する
override_default_from_envar() デフォルト値を環境変数で指定する
required() flagやargを必須の値とする
hidden() スクリプトから指定はできるが、helpには表示しないようにする

まとめ

駆け足となりましたが、Getopt::Kingpinの基本的な使い方を紹介しました。

直感的な形でflagargを定義でき、ヘルプも自動生成されるので使い勝手がとても良いです。
この使い勝手部分はオリジナルを作ったalecthomas氏が素晴らしいという事なのですが、
perlでもgolangでも同じように引数解析ができるようになったので、とても満足しています。

良かったら使ってみてください。

2016/12/03 追記
以下に関連記事を作成しました。