0

Is there an equivalent in Rust for something like:

os.run("/bin/bash ln -s /dir1 /dir2");

I want the ability to spawn a process using a string expression similar to one I would use in a ptty.

The only utility I've found for doing this is std::process::Command, but it's not well documented and seems too complex and hard to debug.

There is In Rust, how do I invoke a system command and capture its output? that gives std::process::Command as an answer, hence why I specified finding it as a possible option. However, I'm looking for a lower level interface to make std::process::Command execute a single string as a query rather than forcing me to feed it the arguments one by one.

Shepmaster
  • 388,571
  • 95
  • 1,107
  • 1,366
George
  • 3,521
  • 4
  • 30
  • 75
  • 1
    Possible duplicate of [In Rust, how do I invoke a system command and capture its output?](https://stackoverflow.com/questions/21011330/in-rust-how-do-i-invoke-a-system-command-and-capture-its-output) – Malice Aug 14 '17 at 18:12
  • 1
    @Malice Please read the post before reporting a duplicate or explain why it is a duplicate. I specifically asked for a lower level interface that is not std::process::Command – George Aug 14 '17 at 18:14
  • 3
    Can you expand upon what you mean by a "lower level interface" and why you require one? Creating a subprocess to execute a command is inherently challenging and error-prone which might explain why `std::process::Command` may seem complex to you. I would imagine any lower level interface would be just as complex. As far as documentation, this seems pretty good to me - https://doc.rust-lang.org/std/process/struct.Command.html. If you have a specific question about the docs/using Command, please edit your question to address that. – user1413793 Aug 14 '17 at 18:23
  • 5
    A single string is *not* a lower-level interface. In a command-line shell (like Windows' cmd or *nix bash), the single string gets parsed and split into components, and those components get put in place in the memory in order to execute the command as you have desired. The `std::process:Command` interface *is* the lower-level interface here, and you can easily write a parser for your *expected* syntax, to take one string and split it into something feedable to this API. But, that's higher-level logic and is left up to your taste and need. – behnam Aug 14 '17 at 18:28
  • 1
    I think `std::process:Command` gives you more control rather than a string command – Malice Aug 14 '17 at 18:31
  • 2
    If you want to talk about "complex and hard to debug", there's little more complex than having code you're running go through a shell. Trying to cover the corner cases if you substitute untrusted data in is **hard** -- as in, it's been the cause of many, many major security bugs, including ones in products made by people who should have known better. I've caught some of those (shell injection) bugs myself. Don't open yourself up -- **use something that maps to the OS interface, which accepts a single array of C strings as argv, and optionally another to specify the environment**. – Charles Duffy Aug 14 '17 at 18:51
  • If the OP is truly interested in a lower level interface, they should check out https://docs.rs/nix/0.17.0/nix/unistd/index.html - it supports many platforms. You would call `fork` -> `execv` (in the child). This is certainly not easier to use, but is technically a thin wrapper around what the standard library's `Command` will do on unix systems. – chub500 May 14 '20 at 21:06

1 Answers1

4

No, there is no such thing available in the standard library. As mentioned in the comments, Command is the lower level interface. Shells and other tools that take a single string have to do exceedingly clever parsing of the string in order to split it back up into pieces. This parsing is non-trivial and may differ between shells!

You can always write your own simplified parser, of course:

use std::process::Command;

fn main() {
    let args = "ls -l /etc /tmp";
    let args: Vec<_> = args.split(" ").collect();

    let output = Command::new(args[0])
        .args(&args[1..])
        .output()
        .expect("Couldn't run it");

    println!("{:?}", ::std::str::from_utf8(&output.stdout));
    println!("{:?}", ::std::str::from_utf8(&output.stderr));
}

but it's not well documented

I'm obviously biased, but I don't understand how it could be more documented. Every useful method has prose describing it and examples demonstrating it.

and seems too complex

I'm not sure why; perhaps the amount of choice is overwhelming, but realistically that control is needed.

and hard to debug.

I'm not sure what debugging needs to be done — either the code will compile or not, then it will execute or not. Compiler errors are frequently useful, runtime errors of this nature usually depend on the OS.

Shepmaster
  • 388,571
  • 95
  • 1,107
  • 1,366