【问题标题】:Execute any bash command, get the results of stdout/stderr immediatly and use stdin执行任何 bash 命令,立即获取 stdout/stderr 的结果并使用 stdin
【发布时间】:2016-07-24 11:23:42
【问题描述】:

我想执行任何 bash 命令。我找到了Command::new,但我无法执行诸如ls ; sleep 1; ls 之类的“复杂”命令。此外,即使我将它放在 bash 脚本中并执行它,我也只会在脚本末尾得到结果(正如流程文档中所解释的那样)。我想在命令打印出来后立即得到结果(并且能够读取输入),就像我们在 bash 中一样。

【问题讨论】:

  • “并且能够读取输入”是什么意思?
  • 我的意思是,如果你从命令行启动一个程序:./myprog,程序通常会等待你输入一些数据,例如,如果它是一个命令行游戏,它可能会问一个号码。当我使用 Command::new() 时,如果它们是生锈的 read_line,它会立即终止它。没时间输入任何东西。我的意思是我真的很想表现得像从命令行执行程序一样。

标签: process rust output exec


【解决方案1】:

Command::new 确实是要走的路,但它是用来执行程序的。 ls ; sleep 1; ls 不是程序,它是一些 shell 的指令。如果您想执行类似的操作,则需要让 shell 为您解释:

Command::new("/usr/bin/sh").args(&["-c", "ls ; sleep 1; ls"])
// your complex command is just an argument for the shell

获取输出有两种方式:

  • output 方法被阻塞并返回命令的输出和退出状态。
  • spawn 方法是非阻塞的,并返回一个包含子进程stdinstdoutstderr 的句柄,以便您可以与子进程通信,并返回一个wait 方法等待它干净利落地退出。请注意,默认情况下,子文件会继承其父文件描述符,您可能希望改为设置管道:

你应该使用类似的东西:

let child = Command::new("/usr/bin/sh")
                .args(&["-c", "ls  sleep 1 ls"])
                .stderr(std::process::Stdio::null()) // don't care about stderr
                .stdout(std::process::Stdio::piped()) // set up stdout so we can read it
                .stdin(std::process::Stdio::piped()) // set up stdin so we can write on it
                .spawn().expect("Could not run the command"); // finally run the command

write_something_on(child.stdin);
read(child.stdout);

【讨论】:

  • 谢谢,我注释了包含piped()null() 的行,因为我想使用父文件描述符。
  • 由于 Command 遵循构建器模式,因此将其构造成这样更习惯:play.rust-lang.org/…
  • @NateMara 其实我最初写的是gist.github.com/2c21ce9e7b919b30cb1444548dc897d9,很惊讶它用&mut self而不是self。无论如何你是对的,我会编辑我的答案,谢谢。
  • 我认为大多数建设者使用&mut self
  • 也许,我并没有真正注意这一点。对于self,不注意的人很有可能会写builder.foo(); builder.bar();而忽略结果,这可能就是原因。不过,这可以通过 must_use 注释来解决。不知道,我只是惊讶了一下。
猜你喜欢
  • 2021-05-29
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2016-03-21
  • 1970-01-01
  • 2019-12-03
  • 2011-11-03
相关资源
最近更新 更多