使用'bash -c'时std :: process:Command不返回Err()结果

Jua*_*ias 4 bash command-line rust

我试图了解为什么Err()使用bash -c表达式运行命令时没有得到结果。

这是一个示例,下面是输出。我希望out2out3是一个Err(),但是out3是一种Ok()与失败的状态。

bash -c用来从给定的字符串执行命令,这很容易。

可以Err()使用bash -c语法获得结果吗?

#![allow(unused)]

use std::process::{Command, Output};

fn main() {
    let out1 = Command::new("bash").arg("-c").arg("ls").output();
    println!("out1: {:?}", out1);

    let out2 = Command::new("wrongcommand").arg("-c").arg("ls").output();
    println!("out2: {:?}", out2);

    let out3 = Command::new("bash").arg("-c").arg("wrongcommand").output();
    println!("out3: {:?}", out3);
}
Run Code Online (Sandbox Code Playgroud)

输出:

out1: Ok(Output { status: ExitStatus(ExitStatus(0)), stdout: "Cargo.lock\nCargo.toml\ncrate-information.json\nsrc\ntarget\n", stderr: "" })
out2: Err(Os { code: 2, kind: NotFound, message: "No such file or directory" })
out3: Ok(Output { status: ExitStatus(ExitStatus(32512)), stdout: "", stderr: "bash: wrongcommand: command not found\n" })
Run Code Online (Sandbox Code Playgroud)

我从命令行尝试过

$ bash -c wrongcommand
Run Code Online (Sandbox Code Playgroud)

$ wrongcommand
Run Code Online (Sandbox Code Playgroud)

两者都返回相同的退出代码(127)。这就是为什么我期望Command以相同的方式失败的原因。

Séb*_*uld 5

这很容易解释。遵循错误代码列表

out1Ok出于明显的原因

out2是一种Err类型,因为Command直接查找该过程,找不到它,然后返回了ENOENT(代码2)。此错误发生锈中,实际上未执行任何操作。

out3Ok因为运行的进程Commandbash,并且它返回了其状态。在这种情况下,它不会找到命令,因此按bash状态返回127。但是,这并不容易,因为中包含了附加的信息层ExitStatus。在unix上,当进程失败时,它实际上返回一个16位/ 32位整数(基于platform / libc / etc),分为两个:

  • 最高位是触发返回的信号
  • 最低的8位是进程的返回状态

而且,毫不奇怪,如果我们将32512 8位右移(这是一个u16),我们将得到127!

要点很简单:

  • Err 绝对意味着该流程未运行
  • Ok表示主流程已运行,但您需要检查ExitStatus::success()以确认其确实已完成(即退出状态为0)

您可以这样恢复它:

Command::new("bash").arg("-c").arg("wrongcommand").output().and_then(|r| match r.status.success() {
  true => Ok(r),
  false => Err(io::Error::new(io::ErrorKind::InvalidData, "Process error"))
});
Run Code Online (Sandbox Code Playgroud)

您可以在操场上玩。success()是子进程成功的可靠指标;它所做的只是检查退出状态的最低有效8位是否为非零。

显然,如果进程成功返回非零值,则无济于事,但这是另一个问题。