hiro99ma blog

rust: cargo run でのオプション位置

2025/10/21

コマンドラインアプリを作っていて、git みたいにサブコマンド風にしていた。
if args[1] == 'cmd1' みたいな書き方をしていたのだけど、Copilot にレビューしてもらうと clap というクレート?を導入して短く書いてくれた。

そこまではよかったが、その後自分でコマンドに共通するオプションを追加しようとして悩んだのでメモしておこう。
最後まで書いて気付いたけど、clap はほぼ関係なかった。

追加

$ cargo add clap --features "derive"

最初の例

特に意味は無いが、”start” と “stop” のサブコマンドを持つようにする。

use clap::{Parser, Subcommand, CommandFactory};

#[derive(Parser)]
#[command(author, version, about, long_about = None)]
struct Cli {
    #[command(subcommand)]
    command: Option<Commands>,
}

#[derive(Subcommand)]
enum Commands {
    Start,
    Stop,
}

fn main() {
    let cli = Cli::parse();

    match cli.command {
        None => {
            Cli::command().print_help().expect("print help");
            println!();
        }
        Some(Commands::Start) => start(),
        Some(Commands::Stop) => stop(),
    }
}

fn start() {
    println!("Start!");
}

fn stop() {
    println!("Stop!!");
}

共通するオプション

struct Cli#[arg()] をすると共通というかサブコマンドごとではないオプション指定になる。 今回は短く -t だけにした。

use clap::{Parser, Subcommand, CommandFactory};

#[derive(Parser)]
#[command(author, version, about, long_about = None)]
struct Cli {
    #[command(subcommand)]
    command: Option<Commands>,

    #[arg(short, default_value_t=5)]
    time: u32,
}

#[derive(Subcommand)]
enum Commands {
    Start,
    Stop,
}

fn main() {
    let cli = Cli::parse();

    match cli.command {
        None => {
            Cli::command().print_help().expect("print help");
            println!();
        }
        Some(Commands::Start) => start(cli.time),
        Some(Commands::Stop) => stop(cli.time),
    }
}

fn start(time: u32) {
    println!("Start({})!", time);
}

fn stop(time: u32) {
    println!("Stop({})!!", time);
}

“help” でオプションに追加されている。

Usage: hello [OPTIONS] [COMMAND]

Commands:
  start  
  stop   
  help   Print this message or the help of the given subcommand(s)

Options:
  -t <TIME>      [default: 5]
  -h, --help     Print help
  -V, --version  Print version

サブコマンドの前に [OPTIONS] があるのでそこに書けば良いのだろう。
という予想は外れた。

$ cargo run -t 10 start
error: unexpected argument '-t' found

  tip: a similar argument exists: '--target'

Usage: cargo run [OPTIONS] [ARGS]...

For more information, try '--help'.

これは cargo run を使っているせいである。
npm start などと同じように -- を使って “cargo のオプションではないですよ” を明示する。

$ cargo run -- -t 10 start
    Finished `dev` profile [unoptimized + debuginfo] target(s) in 0.11s
     Running `target/debug/hello -t 10 start`
Start(10)!

コマンドを直接実行する場合はもちろんそのままでよい。

$ ./target/debug/hello -t 10 start
Start(10)!

writer: hiro99ma
tags: Rust言語


 <🏠 Top page
コメント(Google Formへ飛びます)

GitHub

X/Twitter

Homepage

About me