🦀
RustのコマンドラインライブラリArghの使い方
Rustでコマンドライン引数を渡す時に便利な、Arghというライブラリの利用方法をまとめます。
tokio-rs/tlsのexamplesコードがすっきり書けていて、何のライブラリを使っているのかと調べてみるとArghというライブラリでした。Googleのレポジトリにあるので、Googleの人が作っているようです。
Arghとは
- コマンドライン引数をパースするためのライブラリです。
- パースする引数はアトリビュートを使って指定するので、コードがとてもすっきり書けます。
Arghでサポートされている機能
リッチな機能はありませんが、1.6時点で主に以下の機能がサポートされていました。
- 通常の引数(
--arg
のようなタイプ)のサポート。 - 通常の引数の短縮指定のサポート(
--loglevel
を-l
みたいに書く)やデフォルト値の設定、任意or必須かの指定。 - Positional Arguments(
command arg1 arg2 ..
の様に順番で引数が決定するタイプ)のサポート。 - サブコマンドのサポート。
利用例
それでは、実際のコードサンプルを見ていきましょう。Cargo.toml
には、0.1
をdependencies
に指定しましたが、執筆時のバージョンは0.16
です。
[dependencies]
argh = "0.1"
例1. 通常の引数
READMEにあった例にもう少しサンプルを加えたものです。
use argh::FromArgs;
#[derive(FromArgs)]
/// Reach new heights.
struct GoUp {
/// whether or not to jump
#[argh(switch, short = 'j')]
jump: bool,
/// how high to go
#[argh(option, default = "default_height()")]
height: usize,
/// an optional nickname for the pilot
#[argh(option)]
pilot_nickname: Option<String>,
/// an optional direction which is "up" by default
#[argh(option, default = "String::from(\"only up\")")]
direction: String,
}
fn default_height() -> usize {
5
}
fn main() {
let up: GoUp = argh::from_env();
println!("height is {}", up.height);
println!("direction is {}", up.direction);
if up.jump {
println!("jump!");
}
match up.pilot_nickname {
None => println!("pilot name is not specified"),
Some(name) => {
println!("pilot name is {}", name)
},
}
}
これをオプションを付けて実行すると次のようになります。
$ simple --pilot-nickname Mike -j
height is 5
direction is only up
jump!
pilot name is Mike
例2. Positional Arguments
次は、./command arg1 arg2 arg3 ...
のように順番でコマンドの引数を特定する例です。
struct内の順序が引数の順序になり、最後の引数をvector
にすれば、可変長の引数を渡すことも可能です。
use argh::FromArgs;
#[derive(FromArgs)]
/// Demonstration for positional arguments.
struct PositionalDemo {
#[argh(positional)]
first: String,
#[argh(positional)]
others: Vec<String>,
}
fn main() {
let demo: PositionalDemo = argh::from_env();
println!("the first arg is {}", demo.first);
println!("the other argument is {:?}", demo.others);
}
これをオプションを付けて実行すると次のようになります。
$ positional arg1 arg2 arg3 arg4
the first arg is arg1
the other argument is ["arg2", "arg3", "arg4"]
例3. サブコマンド
最後にサブコマンドの使い方です。これもREADMEにある例と同じですが、実行時のアウトプットも参考に載せておきます。
use argh::FromArgs;
#[derive(FromArgs, PartialEq, Debug)]
/// Top-level command.
struct TopLevel {
#[argh(subcommand)]
nested: MySubCommandEnum,
}
#[derive(FromArgs, PartialEq, Debug)]
#[argh(subcommand)]
enum MySubCommandEnum {
One(SubCommandOne),
Two(SubCommandTwo),
}
#[derive(FromArgs, PartialEq, Debug)]
/// First subcommand.
#[argh(subcommand, name = "one")]
struct SubCommandOne {
#[argh(option)]
/// how many x
x: usize,
}
#[derive(FromArgs, PartialEq, Debug)]
/// Second subcommand.
#[argh(subcommand, name = "two")]
struct SubCommandTwo {
#[argh(switch)]
/// whether to fooey
fooey: bool,
}
fn main() {
let demo: TopLevel = argh::from_env();
println!("command:\n {:?}", demo.nested);
}
one
とtwo
というサブコマンドができ、以下のようにサブコマンドのコマンドも指定できます。
$ subcommand one --x 5
command:
One(SubCommandOne { x: 5 })
$ subcommand two --fooey
command:
Two(SubCommandTwo { fooey: true })
まとめ
Go言語のCobraのようなリッチな機能はないものの、アトリビュートですっきりしたコードが書けるのはとても魅力的でした。
実際に動かしながら理解したいという方のために、サンプルコードが少しでも時間短縮に役立てば幸いです。
Discussion