本連載では第一線のPerlハッカーが回替わりで執筆していきます。今回のハッカーはふしはらかんさんで、
本稿のサンプルコードは、
コマンドラインツールを作ろう
本連載を読まれているみなさんは、
今回は、Smart::Options
を中心に紹介していきます。
Smart::Optionsによるコマンドライン引数の利用
コマンドラインツールを実行する際に、Smart::Options
の具体的な使い方までを見ていきましょう。
コマンドライン引数はなぜ必要か
コマンドライン引数は空白で区切って複数の値を渡すのが基本ですが、
$ command -a -bc -d オプション値 --execute --file=/path/
to/file 引数1 引数2 引数3
-
-a
)-bc
のように英字を複数書くと複数のオプションを一度に指定できます。
オプションに値を持たせる場合、-d オプション値
のように空白を空けてから値を書きます。もし値に空白を含めたい場合は、-d "値 値"
のようにダブルクオートで囲みます。
オプション名を2文字以上にしたい場合は--
--execute
)。この場合、=
--file=path
)。GNUスタイルでは、--version
でのバージョン表示と、--help
でのUsage
多くのプログラミング言語では、@ARGV
として参照できるようになっています。
#!/usr/bin/perl
use strict;
use warnings;
print join("\n", @ARGV);
このコードを実行すると、
$ perl cmd.pl -a -bc -d FooBar arg1 arg2
-a
-bc
-d
FooBar
arg1
arg2
引数をシンプルに利用する
前項のサンプルコードでコマンドライン引数を配列として取得できましたが、-bc
というオプションからb
オプションとc
オプションが有効になっていることを知ったり、d
オプションの値としてFooBar
が渡されていることを知ったりするには、@ARGV
を解析するプログラムを実装する必要があります。
PerlにはGetOpt::Long
というモジュールが標準添付されているほか、Smart::Options
というライブラリを紹介します。
Smart::Options
はNode.optimist
を参考に実装したもので、Smart::Options
を使った形にあらためてみます。
#!/usr/bin/perl
use strict;
use warnings;
use Data::Dumper;
use Smart::Options;
print Dumper(argv(@ARGV));
argv()
はSmart::Options
によってインポートされた関数で、Data::Dumper
でハッシュの中身をそのまま出力しているので、
$ perl cmd_smart.pl -a -bc -d FooBar arg1 arg2
$VAR1 = {
'_' => [
'arg1',
'arg2'
],
'd' => 'FooBar',
'c' => 1,
'b' => 1,
'a' => 1
};
結果を見てわかるとおり、-a
、-b
など)_
の項目に配列リファレンスの形で登録されています。-a
などの値を持たないオプションtrue
)1
が値として入っていますので、
my $opt = argv();
if ($opt->{a}) {
# -aが渡されたときにやる処理
}
のように書けます。ちなみにこのコードではargv()
に引数を渡していませんが、@ARGV
を引数として使用します。
このようにSmart::Options
を導入してargv()
を使うだけで、
オプションを定義して便利に使う
Smart::Options
ではオプションの定義を事前に登録することで、
my $opt = Smart::Options->new;
$opt = $opt->alias(f => 'file');
print Dumper($opt->parse(qw/-f filename/));
先ほどまではargv()
関数を使ってきましたが、Smart::Options->new->parse
のショートカットです。Smart::Options
の本来の使い方は、Smart::Options
のオブジェクトを生成してオプション定義を登録していき、parse
メソッドを実行して戻り値を受け取る、alias
メソッドを含め、parse
を実行できます。
Smart::Options->new->alias(f => 'file')
->demand('f')
->describe(f => 'File Name')
->parse();
alias ── オプションに別名を付ける
alias
はオプションの別名を定義します。file
というオプション名を短くf
でも指定できるようにする、
my $opt = Smart::Options->new;
$opt->parse(qw/-f filename/);
# => { 'f' => 'filename' }
$opt->alias(f => 'file')->parse(qw/-f filename/);
# => { 'file' => 'filename' }
以降のコード例では同様の表記が続きますので、$opt
はあらかじめSmart::Options->new
で初期化されているものとします。実際に動かしてみる場合は、my $opt = Smart::Options->new;
の一文を追記してください。
demand ── オプションを必須にする
demand
はオプションの指定を必須にします。コマンドライン引数で当該オプションが指定されていない場合、
$opt->parse(qw//);
# => { }
$opt->demand('file')->parse(qw//);
# => Error
boolean ── フラグオプションを強制する
boolean
は、
$opt->parse(qw/--flag 100/);
# => { 'flag' => '100' }
$opt->boolean('flag')->parse(qw/--flag 100/);
# => { 'flag' => '1', '_' => ['100'] }
default ── オプションのデフォルト値を指定する
オプションに初期値を持たせるにはdefault
を使います。コマンドライン引数でオプションが指定されていなくても、
$opt->parse(qw//);
# => { }
$opt->default('foo' => 'bar')->parse(qw//);
# => { 'foo' => 'bar' }
help ── オプションの使い方を表示する
help
メソッドを実行すると、
print $opt->describe('foo' => 'Sample option')->help();
# => Usage: /data/cmd_smart_ex.pl
Options:
--foo Sample option
-h, --help Show help
describe
を使うとオプションの説明を登録し、--help
というオプションが表示されていますが、Smart::Options
であらかじめ定義されているオプションで、Smart::Options->new->parse
を実行したときに-h
あるいは--help
というオプションがあった場合はUsageを出力してプログラムを終了します。
なお、--help
オプションとともに必須となっている--version
オプションはあらかじめ定義はされません。コマンドラインツールのバージョンを指定するルールがPerlに存在しないためです。
type ── オプション値の型をチェックする
type
を使うと、
type
としては、Str
Int
Num
$opt->type('num' => 'Int')->parse(qw/--num=string/);
# Error: Value 'string' invalid for option num(Int)
さらに、coerce
を使うと独自のtype
を定義できます。たとえばオプションで年/月/日
という文字列を受け取って、Time::Piece
のインスタンスとして扱いたい場合、Time
というtype
を定義します。
use Time::Piece;
my $r = $opt->coerce(Date => 'Str',
sub { Time::Piece->strptime($_[0], '%Y/%m/%d') }
)->type('day' => 'Date')
->parse(qw{--day=2017/06/24});
# $r->{day}はTime::Pieceのオブジェクトになっている
options ── オプションを一括で定義する
ここまで、options
メソッドを使うと、
$opt->options('f' => {
alias => 'file',
default => '/path/to/file',
describe => 'file path',
})->parse();
$opt->alias('f' => 'file')
->default('file' => '/path/to/file')
->describe('file' => 'file path')->parse();
特殊なコマンドライン引数
Smart::Options
では、
解析の打ち切り
Smart::Options
では、--
というオプション以降はオプションの解析を打ち切って、
$ perl cmd_smart.pl -a -b 100 -- -c -d 100
$VAR1 = {
'b' => '100',
'a' => 1,
'_' => [
'-c',
'-d',
'100'
]
};
--
以降の-c
、-d 100
というコマンドライン引数はそのまま解釈されて、cartonexec
のように、
オプションの否定
--no-foo
のようにオプション名の先頭にno-
を付けると、false
)foo
オプションがデフォルトでtrue
になるように設定されている場合に、false
するために使います。
オプション値のネスト
--foo.
のようにオプション名の中に.
$ perl cmd_smart.pl --foo.bar=10 --foo.baz=20
$VAR1 = {
'_' => [],
'foo' => {
'baz' => '20',
'bar' => '10'
}
};
オプションの種類が多くてオプション名が衝突しそうなときなどに使えます。もっとも、
Smart::Options::Declareによる直感的なコマンドライン引数の利用
argv()
を実行して解析結果のハッシュリファレンスを受け取るSmart::Options
の基本的な使い方は直感的ですが、Smart::Options
に付属するSmart::Options::Declare
というモジュールを使います。
use Smart::Options::Declare;
opts my $foo => 'Str',
my $bar => { isa => 'Int', default => 4 };
opts
に続いてmy
で変数定義をすると、type
やデフォルト値なども定義できます。
上記のコードでは、@ARGV
の中身が--foo
、string
の配列のとき、$foo
の内容が"string"
という文字列、$bar
の内容が数値の4になります。
サブコマンドを利用する
Gitコマンドは、add
、commit
、pull
、push
などいろいろなサブコマンドを指定して複数の機能を切り替えて実行できます。
$ git add file
$ git push origin master
Smart::Options
では、
# コマンド全体のオプションの指定
$opt->boolean('force')->alias(f => 'force');
# addサブコマンドを定義
$opt->subcmd(add => Smart::Options->new->demand('file'));
# pushサブコマンドを定義
my $push_cmd = Smart::Options->new
->describe(r => 'repository');
$opt->subcmd(push => $push_cmd);
my $result = $opt->parse(qw/-f add --file=filename/);
{
'force' => 1,
'command' => 'add',
'cmd_option' => {
file => 'filename',
'_' => []
}
}
subcmd
メソッドに、Smart::Options
のオブジェクトを渡してサブコマンドを定義していきます。parse
メソッドの戻り値のキー名command
に指定されたサブコマンドが、cmd_
にコマンドラインオプションの解析結果が入ります。
<続きの
本誌最新号をチェック!
WEB+DB PRESS Vol.130
2022年8月24日発売
B5判/
定価1,628円
ISBN978-4-297-13000-8
- 特集1
イミュータブルデータモデルで始める
実践データモデリング
業務の複雑さをシンプルに表現! - 特集2
いまはじめるFlutter
iOS/Android両対応アプリを開発してみよう - 特集3
作って学ぶWeb3
ブロックチェーン、スマートコントラクト、 NFT