Lambdaカクテル

京都在住Webエンジニアの日記です

コマンドが失敗するまで実行し続けるツールをRustで書いた

さんざん既出&&shでやれという話がありそうだけど,最近rustに興味でてきたので書いてみた。ちなみにRustは初心者です。

github.com

動機

ぜんぜんRustとは関係ないプロダクトの開発をしているのだが,確率的に失敗するテストがあって困っていた。とにかく失敗するまで動かしてほしいのだが,せっかくだし最近興味があったRustで書いてみようと思った。 Rustは小さなバイナリを吐けて高速なので,この目的に適していると考えた。実際今回も300KiBくらいのバイナリに納まった。Cほどではないが十分だと思う。

動作

引数として渡したコマンドを実行する。失敗するとすぐ返ってくる。

$ all-you-need-is-die false
status: exit code: 1
dead!

成功した(exit code == 0)なら,再度実行する。

コード

これだけ。rustらしいコードになっているかというとそうでもないけど,書いた体験は良かった。

use std::process::Command;
use std::env;
use std::io::{self, Write};

fn main() {
    // get args
    let args: Vec<String> = env::args().collect();
 
    //execute command
    let mut cmd = Command::new(&args[1]);
    cmd.args(&args[2..]);
    let mut output = cmd.output();
    while let Ok(o) = output {
        println!("status: {}", o.status);
        io::stdout().write_all(&o.stdout).unwrap();
        io::stderr().write_all(&o.stderr).unwrap();
        if o.status.code() != Some(0) { break; }
        output = cmd.output();
    }

    println!("dead!");
}

感想

Rustは初心者だけど,ドキュメントが充実していてサンプルが豊富なので助かる。コンパイラも親切で,指示された通りにしておけばだいたいどうにかなる。

Scalaをやっていたので,match式はすんなり理解できたし,Some(42)といった記法もそのままだなと思った。シンプルだけど関数型ライクな機能も豊富,というイメージを受けた。コレクションメソッドも豊富そうな印象。 Goはシンプルさに舵を切っているけれど,Rustはより低レイヤに近いような感じがする。

参照渡しと値渡しとの間の絶妙な着地点を,所有権というモデルですりあわせているのが面白いと思う。メモリを無駄にしないようにしつつ,安全に利便性を高めている。

cargoもよくできてるなという印象がある。