24

I want to execute a shell command in Rust. In Python I can do this:

import os
cmd = r'echo "test" >> ~/test.txt'
os.system(cmd)

But Rust only has std::process::Command. How can I execute a shell command like cd xxx && touch abc.txt?

Shepmaster
  • 388,571
  • 95
  • 1,107
  • 1,366
Peiyuan Li
  • 253
  • 1
  • 2
  • 5

3 Answers3

38

Everybody is looking for:

use std::process::Command;

fn main() {
    let output = Command::new("echo")
        .arg("Hello world")
        .output()
        .expect("Failed to execute command");

    assert_eq!(b"Hello world\n", output.stdout.as_slice());
}

For more information and examples, see the docs.

You wanted to simulate &&. std::process::Command has a status method that returns a Result<T> and Result implements and_then. You can use and_then like a && but in more safe Rust way :)

Shepmaster
  • 388,571
  • 95
  • 1,107
  • 1,366
S.R
  • 2,411
  • 1
  • 22
  • 33
  • 5
    Except that `Command::new ("cd").arg ("foo").status()` will always [fail](https://play.integer32.com/?gist=572ca6d0639209b4933d114c151dde71&version=stable&mode=debug)… – Jmb May 31 '18 at 07:08
  • 1
    @Jmb Do you know why? – S.R Oct 09 '18 at 07:59
  • 8
    Because `cd` is not an executable, it is an internal shell command and as such can't be run directly from a non-shell program. You could always do `Command::new ("/bin/sh").args (&["-c", "cd", "foo"])` to run the command in a shell but that's a no-op that won't affect the calling process. – Jmb Oct 09 '18 at 08:34
  • that didn't work for me, I recieved a runtime error. when I was running on windows I had to do Command::new("cmd") this than ran the code fine. – Gloat Mar 13 '20 at 06:55
  • 1
    @DevinB Rust code works on Windows and Linux but the parameters are system dependent. Example is for Linux. Feel free to edit this answer if you know example that works both on Windows and Linux. – S.R Mar 13 '20 at 07:09
  • @Jmb wow that's an excellent answer in search of a question, I know I've been having problems with that (cd not being an executable, or similar things) many times but explaining is succinctly makes it very clear(er) suddenly. – Félix Adriyel Gagnon-Grenier Sep 20 '21 at 13:24
9

You should really avoid system. What it does depends on what shell is in use and what operating system you're on (your example almost certainly won't do what you expect on Windows).

If you really, desperately need to invoke some commands with a shell, you can do marginally better by just executing the shell directly (like using the -c switch for bash).

If, for some reason, the above isn't feasible and you can guarantee your program will only run on systems where the shell in question is available and users will not be running anything else...

...then you can just use the system call from libc just as you would from regular C. This counts as FFI, so you'll probably want to look at std::ffi::CStr.

DK.
  • 55,277
  • 5
  • 189
  • 162
2

For anyone looking for a way to set the current directory for the subprocess running the command i. e. run "ls" in some dir there's Command::current_dir. Usage:

use std::process::Command;

Command::new("ls")
        .current_dir("/bin")
        .spawn()
        .expect("ls command failed to start");
micoay
  • 63
  • 7