LoginSignup
4

More than 1 year has passed since last update.

posted at

updated at

Organization

Rust で structopt で簡単 CLI ツール

この記事は ユニークビジョン株式会社 Advent Calendar 2020 の 11 日目の記事です。

はじめに

Rust 勉強中です。(初心者です)
Rust で CLI ツールを作ろうとしたときに structopt が便利だったのでご紹介します。

... ちなみに、clap というクレートでも同じ書き方でコマンドを定義できるようです。
https://github.com/clap-rs/clap#using-derive-macros

The first example shows the simplest way to use clap, by defining a struct. If you're familiar with the structopt crate you're in luck, it's the same! (In fact it's the exact same code running under the covers!)

(structopt は clap を使って実装されているので、clap を使った例のほうがよかったのかもしれません)

準備

プロジェクトを用意します。

cargo new my-cli

Cargo.tomldependencies に以下を追加します。

structopt = "0.3.21"

引数として受け取る

引数を受け取って、そのまま返す簡単なコマンドを作成します。

  • 構造体の定義の上のところに #[derive(StructOpt)] を記述します。
  • from_args() を呼び出すと、実行時に引数から受け取った値を構造体として得ることができます。
use structopt::StructOpt;

#[derive(StructOpt)]
struct Opt {
    name: String,
}

fn main() {
    let opt = Opt::from_args();
    println!("{}", opt.name);
}

実行すると以下のようになります。

$ cargo run hoge
hoge

オプションとして受け取る

オプションとして使いたいメンバには #[structopt(short, long)] を記述します。

  • デフォルトではメンバ変数の名前がオプションの名前として使用されます。
  • short = "g" とすると、そのオプションを -g で呼び出せるようになります。
use structopt::StructOpt;

#[derive(StructOpt)]
struct Opt {
    name: String,
    #[structopt(short = "g", long)]
    greet: bool,
}

fn main() {
    let opt = Opt::from_args();

    if opt.greet {
        println!("Hello, {}!", opt.name);
    } else {
        println!("{}", opt.name);
    }
}
$ cargo run hoge
hoge

$ cargo run hoge --greet
Hello, hoge!

$ cargo run hoge -g
Hello, hoge!

greet 変数の型を Option<String> にすれば文字列を渡せます。

(もしここで Option<String> ではなく String にすれば --greet は必須のオプションになります。)

use structopt::StructOpt;

#[derive(StructOpt)]
struct Opt {
    name: String,
    #[structopt(short = "g", long)]
    greet: Option<String>,
}

fn main() {
    let opt = Opt::from_args();

    match opt.greet {
        Some(greet) => println!("{}, {}!", greet, opt.name),
        None => println!("{}", opt.name),
    }
}
$ cargo run hoge -g Hi
Hi, hoge!

その他

環境変数から値を受け取る

個人的にとても使いやすそうだと思いました。

use structopt::StructOpt;

#[derive(StructOpt)]
struct Opt {
    name: String,
    #[structopt(short = "g", default_value = "Hello", env = "GREET")]
    greet: String,
}

fn main() {
    let opt = Opt::from_args();
    println!("{}, {}!", opt.greet, opt.name);
}
$ cargo run hoge
Hello, hoge!

$ cargo run hoge -g Hi
Hi, hoge!

$ GREET=Hi cargo run hoge
Hi, hoge!

Vec<String>として値を受け取る

たとえば Vec<String> として引数の値を受け取ることができます。

  • min_values = 2 とすると、引数が 1 つしか与えられない場合にエラーになってくれます。
use structopt::StructOpt;

#[derive(StructOpt)]
struct Opt {
    #[structopt(required = true, min_values = 2)]
    names: Vec<String>,
}

fn main() {
    let opt = Opt::from_args();
    println!("Hello! {}!", opt.names.join(", "));
}
$ cargo run hoge fuga
Hello! hoge, fuga!

サブコマンドを作成する

use structopt::StructOpt;

#[derive(StructOpt, Debug)]
/// help comment here!!!
enum Opt {
    /// greet someone
    Greet { name: String },
    /// say goodbye to someone
    Bye {
        name: String,
        #[structopt(short = "f", long)]
        forever: bool,
    },
}

fn main() {
    match Opt::from_args() {
        Opt::Greet { name } => println!("{} さん、こんにちは。", name),
        Opt::Bye { name, forever } => {
            if forever {
                println!("{} さん、永遠にさようなら。", name)
            } else {
                println!("{} さん、さようなら。", name)
            }
        }
    };
}

実行例 :

cargo run help
my-cli 0.1.0
help comment here!!!

USAGE:
    my-cli <SUBCOMMAND>

FLAGS:
    -h, --help       Prints help information
    -V, --version    Prints version information

SUBCOMMANDS:
    bye      say goodbye to someone
    greet    greet someone
    help     Prints this message or the help of the given subcommand(s)
$ cargo run greet hoge
hoge さん、こんにちは。
$ cargo run bye fuga -f
fuga さん、永遠にさようなら。

おわりに

structopt を使用すれば Rust のプログラムを簡単に CLI にできます。ぜひ使ってみてください。

簡単ですが以上です。ありがとうございました。

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
What you can do with signing up
4