166

Is there a way to invoke a system command, like ls or fuser in Rust? How about capturing its output?

vallentin
  • 23,478
  • 6
  • 59
  • 81
quux00
  • 13,679
  • 10
  • 57
  • 69

4 Answers4

199

std::process::Command allows for that.

There are multiple ways to spawn a child process and execute an arbitrary command on the machine:

  • spawn — runs the program and returns a value with details
  • output — runs the program and returns the output
  • status — runs the program and returns the exit code

One simple example from the docs:

use std::process::Command;

Command::new("ls")
        .arg("-l")
        .arg("-a")
        .spawn()
        .expect("ls command failed to start");
Shepmaster
  • 388,571
  • 95
  • 1,107
  • 1,366
talles
  • 14,356
  • 8
  • 45
  • 58
  • 11
    What if i need to get real-time output. I think `output` function returns Vec after completion of process. So, in case if we run something like `Command("ping google.com")`. Is this possible to get this commands output as it will not finish but I want to print its logs. Please suggest. – GrvTyagi Jan 10 '20 at 18:37
  • 7
    @GrvTyagi: `spawn`, mentioned in this answer, returns a [`Child`](https://doc.rust-lang.org/std/process/struct.Child.html) result with standard I/O streams. – Ry- Jan 11 '20 at 04:13
  • 3
    Building off of this excellent answer, I also found [this answer](https://stackoverflow.com/a/49597789/11639533) helpful for understanding how to interact with stdin/stdout. – Michael Noguera Jul 25 '20 at 19:16
94

a very clear example from the docs:

use std::process::Command;
let output = Command::new("/bin/cat")
                     .arg("file.txt")
                     .output()
                     .expect("failed to execute process");

println!("status: {}", output.status);
println!("stdout: {}", String::from_utf8_lossy(&output.stdout));
println!("stderr: {}", String::from_utf8_lossy(&output.stderr));

assert!(output.status.success());
mrtechmaker
  • 1,769
  • 12
  • 11
9

It is indeed possible! The relevant module is std::run.

let mut options = std::run::ProcessOptions::new();
let process = std::run::Process::new("ls", &[your, arguments], options);

ProcessOptions’ standard file descriptors default to None (create a new pipe), so you can just use process.output() (for example) to read from its output.

If you want to run the command and get all its output after it’s done, there’s wait_with_output for that.

Process::new, as of yesterday, returns an Option<Process> instead of a Process, by the way.

Ry-
  • 218,210
  • 55
  • 464
  • 476
0

Command builds and configures a child process. When you create a new instance of Command and specify the command you want to execute, any arguments, environment variables, and other settings, you are defining the configuration for a child process.

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

let system_command = "echo";
let argument = "Hello World";

let echo_hello: std::process::Output = Command::new(system_command)
                        .arg(argument)
                        //.current_dir(TEST_PATH)
                        // Stdio::piped() creates pipes to capture stdout and stderr of a child process which is created by Command. 
                        // we are telling the Command to create a pipe to capture the standard output (stdout) of the child process.
                        .stdout(Stdio::piped())
                        // creating a pipe to capture the standard error (stderr) of the child process.
                        .stderr(Stdio::piped())
                        // output() executes the child process synchronously and captures its output. 
                        //It returns a std::process::Output struct containing information about the process's exit status, stdout, and stderr.
                        .output()
                        .expect("Failed to echo");

you could use spawn() instead of output() to execute the child process asynchronously. Using spawn() will allow the child process to run independently of the parent process. spawn() returns

std::process::Child 

If you need to terminate the child process prematurely for some reason, you can call the kill() method on the std::process::Child handle. On the other hand, once the output() method is called, the child process runs to completion, and there is no direct mechanism provided by output() to terminate the process prematurely.

Yilmaz
  • 35,338
  • 10
  • 157
  • 202