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