Running multiple shell commands using std::process::Command - rust

I am trying to insert multiple commands using std::process::Command on Rust instead of running a
bash script. I have read the concept of running multiple commands using the example cited here, from the execute crate:
https://docs.rs/execute/latest/execute/#execute-multiple-commands-and-pipe-them-together.
use std::process::{Command, Stdio};
use execute::Execute;
let mut command1 = Command::new("echo");
command1.arg("HELLO WORLD");
let mut command2 = Command::new("cut");
command2.arg("-d").arg(" ").arg("-f").arg("1");
let mut command3 = Command::new("tr");
command3.arg("A-Z").arg("a-z");
command3.stdout(Stdio::piped());
let output = command1.execute_multiple_output(&mut [&mut command2, &mut command3]).unwrap();
assert_eq!(b"hello\n", output.stdout.as_slice());
The problem is these commands are being written in a scattered format. I would like to know if there are better ways to add subcommands directly as arguments under Command::new() instead of having to segregate them as command1, command2 etc.

Related

How to print ssh output in rust

I am making an application a part of which it ssh into a server and runs some commands.
let mut s= session.channel_new().unwrap();
s.open_session().unwrap();
s.request_exec(input.as_ref()).unwrap();
s.send_eof().unwrap();
//standard output
let mut buf=Vec::new();
s.stdout().read_to_end(&mut buf).unwrap();
println!("{}", String::from_utf8_lossy(&buf));
//error output
let mut buf=Vec::new();
s.stderr().read_to_end(&mut buf).unwrap();
println!("{}", String::from_utf8_lossy(&buf));
this is what I have so far, but the problem am facing is that it returns terminal output in two different set, standard and error. by printing it like this I am losing the order of output from the ssh session. lets say i do sudo apt update && sudo apt upgrade and if this has any errors, it'll first print all the stuff that went well and then the error. How can I fix to have a real time output from the ssh session like the one you get from a terminal?
using https://docs.rs/ssh/latest/ssh/ for ssh

How to avoid std::process::Command single quote escaping

I am trying to run an ffmpeg command with a complex filter in Rust, and the std::process::Command blocks me from executing it by escaping the singles quotes, required as is by ffmpeg.
use std::process::Command;
fn main() {
let mut cmd = Command::new("ffmpeg");
cmd.args([
"-filter_complex",
"[video_0]geq=lum='p(X,Y)'[video_0];",
]);
println!("Running command {:?}", cmd);
// Actual:
// Running command "ffmpeg" "-filter_complex" "[video_0]geq=lum=\'p(X,Y)\'[video_0];"
// Expected:
// Running command "ffmpeg" "-filter_complex" "[video_0]geq=lum='p(X,Y)'[video_0];"
}
How can I run this command so that the single quotes are not escaped?
Is this a bug from the Command implementation?
Command's debug view just view the arguments in debug view and that includes escaping characters, but it will still work.

What is the Rust equivalent of the system function in C++? [duplicate]

Is there a way to invoke a system command, like ls or fuser in Rust? How about capturing its output?
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");
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());
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.

How do I execute a command in a subshell in Rust?

In Python, I could do os.system("pip install bs4"). Is there any equivalent in Rust? I've seen std::process::Command, but this seems to fail each time:
use std::process::Command;
Command::new("pip")
.arg("install")
.arg("bs4")
.spawn()
.expect("pip failed");
Is there any way to have the code execute a real shell and have them run in the terminal?
Pip requires root permissions so be sure to run your binary with sufficient privileges.
The following worked for me:
use std::process::Command;
Command::new("pip")
.args(&["install", "bs4"])
.spawn()
.expect("failed to execute process");
Use this to analyze the failure:
use std::process::Command;
let output = Command::new("pip")
.args(&["install", "bs4"])
.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));
Example was derived from here:
How do I invoke a system command in Rust and capture its output?

How do I invoke a system command and capture its output?

Is there a way to invoke a system command, like ls or fuser in Rust? How about capturing its output?
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");
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());
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.

Resources