【问题标题】:How to implement redirection of stdout of a child process to a file?如何实现子进程的标准输出重定向到文件?
【发布时间】:2017-03-10 19:15:12
【问题描述】:

我正在用 Rust 编写的 shell 中实现 I/O 重定向。通过使用带有原始文件描述符的不安全代码和来自 libc crate 的 pipe(),我成功地在两个子进程之间进行管道传输。

当我尝试将最后一个子进程的stdout 重定向到我有权访问的文件时,它失败了:

extern crate libc;
use std::process::{Command, Stdio};
use std::os::unix::io::{FromRawFd, IntoRawFd};
use std::fs::File;
use self::libc::c_int;

fn main() {
    let mut fds = [-1 as c_int, -1 as c_int];
    let fd1 = File::open("test1").unwrap().into_raw_fd();
    let fd2 = File::open("test2").unwrap().into_raw_fd();
    let fd3 = File::open("test3").unwrap().into_raw_fd();
    println!("{:?}, {:?}, {:?}", fd1, fd2, fd3);
    unsafe {
        libc::pipe(&mut fds[0] as *mut c_int);
        let cmd1 = Command::new("ls")
            .arg("/")
            .stdout(Stdio::from_raw_fd(fds[1]))
            .spawn()
            .unwrap();
        let mut cmd2 = Command::new("grep")
            .arg("etc")
            .stdin(Stdio::from_raw_fd(fds[0]))
            .stdout(Stdio::from_raw_fd(fd1))
            .spawn()
            .unwrap();
        let _result = cmd2.wait().unwrap();
    }
}

上一段的结果:

3, 4, 5
grep: write error: Bad file descriptor

似乎文件描述符没有正确返回,但如果没有名为 test1、test2 和 test3 的文件,File::open(_).unwrap() 应该恐慌而不是假装打开了文件。

如果移除对文件的重定向,即只使用管道,则代码可以正常工作。

【问题讨论】:

    标签: rust file-descriptor libc


    【解决方案1】:

    File::open 状态的文档(强调我的):

    尝试以只读模式打开文件。

    切换到File::create 似乎会创建文件并将“etc”写入其中。


    此外,您应该:

    1. 未打开另外 2 个文件 - 没有任何东西会关闭这些文件描述符,因此您有资源泄漏。
    2. 检查pipe的返回值以处理错误。
    3. 查看nix crate
    extern crate libc;
    extern crate nix;
    
    use std::process::{Command, Stdio};
    use std::os::unix::io::{FromRawFd, IntoRawFd};
    use std::fs::File;
    
    use nix::unistd::pipe;
    
    fn main() {
        let fds = pipe().unwrap();
        let fd1 = File::create("test1").unwrap().into_raw_fd();
    
        let (pipe_in, pipe_out, file_out) = unsafe {
            (Stdio::from_raw_fd(fds.0),
             Stdio::from_raw_fd(fds.1),
             Stdio::from_raw_fd(fd1))
        };
    
        Command::new("ls")
            .arg("/")
            .stdout(pipe_out)
            .spawn()
            .unwrap();
    
        let mut cmd2 = Command::new("grep")
            .arg("etc")
            .stdin(pipe_in)
            .stdout(file_out)
            .spawn()
            .unwrap();
    
        cmd2.wait().unwrap();
    }
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2011-01-10
      • 2013-06-02
      • 1970-01-01
      • 2022-12-14
      • 1970-01-01
      • 1970-01-01
      • 2013-07-16
      相关资源
      最近更新 更多