I'm trying to understand why I'm not getting an Err()
result when using bash -c
expression to run a command.
Here is an example and the output below. I expect out2
and out3
to be an Err()
but out3
is an Ok()
with the failed status.
I'm using bash -c
to execute a command from a given string, which is easy.
It's possible to get an Err()
result using bash -c
syntax?
#![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);
}
Output:
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" })
I tried from command line and
$ bash -c wrongcommand
and
$ wrongcommand
and both return the same exit code (127). That's why I expected that Command failed in the same way.
That can be explained pretty easily. Follow along on the list of error codes
out1
is Ok
for obvious reasons
out2
is an Err
type because Command
directly looked for the process, could not find it, and returned ENOENT
(code 2). This error happened within rust, nothing was actually executed.
out3
is Ok
because the process that Command
ran is bash
, and it returned its status. In this case, it wouldn't have found the command, so by bash statuses, it'll have returned 127. However, it's not that easy, because there is an additional layer of information contained in ExitStatus
. On unix, when a process fails, it actually returns a 16bit/32bit integer (based on platform/libc/etc), separated in two:
And, to no surprise, if we shift 32512 8 bits to the right (it was an u16
), we get... 127!
The takeaway is simple:
Err
definitely means the process didn't run Ok
means the main process ran, but you'll need to check ExitStatus::success()
to confirm that it actually did (ie 0 as exit status) You could recover it like so:
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"))
});
You can play with this on the playground . success()
is a decently reliable indicator of child process success; all it does is check if the least significant 8 bits of the exit status is non-zero.
Obviously, this does not help if a process returns non-zero on success, but that's a different problem.
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.