perlで引数処理といえばGetopt::Longがコアモジュールなのもあり、よく使われています。
このページでは、引数処理の新しい選択肢として拙作のGetopt::Kingpinを紹介します。
- https://metacpan.org/pod/Getopt::Kingpin
- 2016/11/17時点のversionは
0.06
です
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
の基本的な使い方を紹介しました。
直感的な形でflag
やarg
を定義でき、ヘルプも自動生成されるので使い勝手がとても良いです。
この使い勝手部分はオリジナルを作ったalecthomas氏が素晴らしいという事なのですが、
perlでもgolangでも同じように引数解析ができるようになったので、とても満足しています。
良かったら使ってみてください。
2016/12/03 追記
以下に関連記事を作成しました。