在Rust中生成进程时重定向stdio的正确方法是什么?

时间:2014-02-05 05:28:18

标签: rust

我看到两种方法(Rust v0.9)。对于下面的示例,假设我想将STDOUT重定向到某个文件。

第一个是获取文件的文件描述符,然后将其传递给std::run::ProcessOptions结构。以下是std::run::process_status的用法:

let mut opt_prog = Process::new(prog, args, ProcessOptions {
    env: None,
    dir: None,
    in_fd:  Some(unsafe { libc::dup(libc::STDIN_FILENO)  }),
    out_fd: Some(unsafe { libc::dup(libc::STDOUT_FILENO) }),
    err_fd: Some(unsafe { libc::dup(libc::STDERR_FILENO) })
});

它获取STDIN,STDOUT和STDERR的常用文件描述符并设置它们。 但是如何获取Rust中打开的任意文件的文件描述符?我还没有找到办法。


第二个选项是通过ProcessOptions::new()使用默认的ProcessOptions,它打开一个到stdin,stdout和stderr的管道,让你抓住它们,如下所示:

let pgm = "ls";
let args = ~[~"-lh"];

match Process::new(pgm, args, ProcessOptions::new()) {
    None => println("fubar"),
    Some(mut p) => {
        {
            let process = &mut p;
            let rdr = process.output();  // grab STDOUT output
            let out = rdr.read_to_str();
            // write output to your file of choice here
        }
        p.close_input();
        p.close_outputs();
        p.finish();
    }
}

我更喜欢第一种方式,但我怀疑第二种方式是采用这种方式。

我不喜欢第二个选项是如果我只想重定向STDOUT而不是其他选项?我现在必须调用process.error()并将其写回STDERR,这看起来很愚蠢。我也必须为STDIN做类似的事情,因为它也被包裹在管道中。

关于最好方法的想法?

1 个答案:

答案 0 :(得分:2)

使用std::os::unix::AsRawFd特征,它使用std::io::fs::File方法扩展与平台无关的as_raw_fd以返回文件描述符。

使用此扩展程序和其他特定于Unix的扩展程序的一种便捷方法是导入std::os::unix::prelude模块。特别是,我最初回答这个问题的例子实际上与文档中的example几乎相同:

#![feature(globs)]

use std::io::fs::File;
use std::os::unix::prelude::*;

fn main() {
    let p = Path::new("/etc/passwd");
    let f = File::open(&p).unwrap();
    let fd = f.as_raw_fd();
    println!("{} fd: {}", p.as_str().unwrap(), fd);
}