blockの巣

Rustのstd::process::Commandで引っかかったところ

2019/12/26 18:30 公開
Rust

git-authorというgitのサブコマンドを作っているときにstd::process::Commandを使用したのですが、output()の返り値ので引っかかったことがあったのでメモがてら書いていきます。


output()Okを返してもコマンドの実行に成功したとは限らない

例えばgit config --local user.nameと同じことをしようと思うと

// outputはio::Result<Output>型
let result = std::process::Command::new("git")
            .arg("config")
            .arg("--local")
            .arg("user.name")
            .output();

となります。

output()Result型を返すのでコマンド実行に失敗すればErrが返ってくるのだろうと考えていましが、実行に失敗してもOkが返ってくるパターンがありました。

例えば

// `git hoge`を実行
let result = std::process::Command::new("git").arg("hoge").output();
let output = result.unwrap();

のように存在しないサブコマンドhogeを実行しようとするとコマンドの実行結果は失敗なのにも関わらずoutput()Okを返します。 ただしoutput.stdoutは空のままでoutput.stderrに文字列が入っています。


また、先程の

// `git config --local user.name`を実行
std::process::Command::new("git")
.arg("config")
.arg("--local")
.arg("user.name")
.output();

も、ローカルのuser.nameが設定されていない時は失敗として扱われますが、output()Okを返します。

Errを返すとき

ではどのようなときにErrを返すかというと

// `fuga`を実行
let output = std::process::Command::new("fuga").output();

のように存在しないコマンドを実行しようとしたときにErrを返しました。

結論

実行に成功したかどうかを確認したい時はoutput()の返り値がOkかどうかに加えてstatus.success()がtrueかどうかを確認しましょう。

let result = std::process::Command::new("command").output();
if let Ok(output) = result {
    if output.status.success() {
        // 成功
    }
    else {
        // 失敗
    }
}
else {
    // 失敗
}