私はこれを行う標準ライブラリに何も表示されません。自分で書くことができないというわけではありません。これはまた、各ファイルディスクリプタの読み取り頻度や、各ファイルディスクリプタのデータの結合方法を決定することを意味します。ここでは、デフォルトのBufReader
サイズを使用してチャンクを読み込み、両方のディスクリプタにデータがある場合は、最初にstdoutデータを格納します。
use std::io::prelude::*;
use std::io::BufReader;
use std::process::{Command, Stdio};
fn main() {
let mut child =
Command::new("/tmp/output")
.stdout(Stdio::piped())
.stderr(Stdio::piped())
.spawn()
.expect("Couldn't run program");
let mut output = Vec::new();
// Should be moved to a function that accepts something implementing `Write`
{
let stdout = child.stdout.as_mut().expect("Wasn't stdout");
let stderr = child.stderr.as_mut().expect("Wasn't stderr");
let mut stdout = BufReader::new(stdout);
let mut stderr = BufReader::new(stderr);
loop {
let (stdout_bytes, stderr_bytes) = match (stdout.fill_buf(), stderr.fill_buf()) {
(Ok(stdout), Ok(stderr)) => {
output.write_all(stdout).expect("Couldn't write");
output.write_all(stderr).expect("Couldn't write");
(stdout.len(), stderr.len())
}
other => panic!("Some better error handling here... {:?}", other)
};
if stdout_bytes == 0 && stderr_bytes == 0 {
// Seems less-than-ideal; should be some way of
// telling if the child has actually exited vs just
// not outputting anything.
break;
}
stdout.consume(stdout_bytes);
stderr.consume(stderr_bytes);
}
}
let status = child.wait().expect("Waiting for child failed");
println!("Finished with status {:?}", status);
println!("Combined output: {:?}", std::str::from_utf8(&output))
}
プロセスがいつ終了するかは、最も大きなギャップです。私はChild
に関連する方法がないことに驚いています。
は、このソリューションでもHow do I prefix Command stdout with [stdout] and [sterr]?
を参照してください、ファイル・ディスクリプタ間のいずれかの本質的な順序はありません。類推として、2つのバケツの水を想像してみてください。バケツを空にして後でそれが再び満たされていることがわかると、2番目のバケツが最初のバケットの後に来ることがわかります。ただし、2つのバケットを空にして後で戻ってきて、両方がいっぱいになると、どのバケットが最初に満たされたかを知ることができません。
インターリーブの「品質」は、各ファイルディスクリプタから読み取る頻度と最初に読み取られるファイルディスクリプタの問題です。非常にタイトなループで各バイトから1バイトを読み取ると、完全に文字化けした結果が得られるかもしれませんが、これは注文に関して最も正確です。同様に、プログラムがstderrに "A"を、そしてstdoutに "B"を出力するが、シェルがstderrの前にstdoutから読み込むと、結果は "BA"になり、逆向きになる。
私は 'let pipe2 = Stdio :: from_raw_fd(pipe.to_raw_fd())'のようなものを探していましたが、ドキュメンテーションの 'AsRawFd'の実装が気にならない。 –
'Stdio :: piped()'が必要なのかどうか分かりませんが、 '.stdout(Stdio :: piped())。stderr(Stdio :: piped())'を使うのはなぜですか? [RustByExample](http://rustbyexample.com/std_misc/process/pipe.html)がこれを行います。 – Manishearth
@Manishearthこれはstdinとstdoutを2つの別々のパイプにリダイレクトするように聞こえます。OPは、その内容の間で注文情報を失うことなく、それらを同じパイプにリダイレクトしたいかもしれません。同等のBourneシェル構造は、例えば、 'output = $(command 2>&1)'です。 – user4815162342