External Command
Run an external command and process stdout
Runsgit log --oneline
using an externalCommand
and inspects theOutput
status to determine if the command was successful. The command output is capturedas a [String
] using [String::from_utf8
].
use anyhow::{Result, anyhow};use std::process::Command;fn main() -> Result<()> { let output = Command::new("git").arg("log").arg("--oneline").output()?; if output.status.success() { let raw_output = String::from_utf8(output.stdout)?; let lines = raw_output.lines(); println!("Found {} lines", lines.count()); Ok(()) } else { return Err(anyhow!("Command executed with failing error code")); }}
Run an external command passing it stdin and check for an error code
Opens thepython
interpreter using an externalCommand
and passes it apython statement for execution.Output
of statement is then parsed.
use anyhow::{Result, anyhow};use std::collections::HashSet;use std::io::Write;use std::process::{Command, Stdio};fn main() -> Result<()> { let mut child = Command::new("python").stdin(Stdio::piped()) .stderr(Stdio::piped()) .stdout(Stdio::piped()) .spawn()?; child.stdin .as_mut() .ok_or_else(|| anyhow!("Child process stdin has not been captured!"))? .write_all(b"import this; copyright(); credits(); exit()")?; let output = child.wait_with_output()?; if output.status.success() { let raw_output = String::from_utf8(output.stdout)?; let words = raw_output.split_whitespace() .map(|s| s.to_lowercase()) .collect::<HashSet<_>>(); println!("Found {} unique words:", words.len()); println!("{:#?}", words); Ok(()) } else { let err = String::from_utf8(output.stderr)?; return Err(anyhow!("External command failed:\n {}", err)); }}
Run piped external commands
Shows up to the 10th biggest files and subdirectories inthe current working directory. It is equivalent to running:du -ah . | sort -hr | head -n 10
.
Command
s represent a process. Output of a child process is captured with aStdio::piped
between parent and child.
use anyhow::Result;use std::process::{Command, Stdio};fn main() -> Result<()> { let directory = std::env::current_dir()?; let mut du_output_child = Command::new("du") .arg("-ah") .arg(&directory) .stdout(Stdio::piped()) .spawn()?; if let Some(du_output) = du_output_child.stdout.take() { let mut sort_output_child = Command::new("sort") .arg("-hr") .stdin(du_output) .stdout(Stdio::piped()) .spawn()?; du_output_child.wait()?; if let Some(sort_output) = sort_output_child.stdout.take() { let head_output_child = Command::new("head") .args(&["-n", "10"]) .stdin(sort_output) .stdout(Stdio::piped()) .spawn()?; let head_stdout = head_output_child.wait_with_output()?; sort_output_child.wait()?; println!( "Top 10 biggest files and directories in '{}':\n{}", directory.display(), String::from_utf8(head_stdout.stdout).unwrap() ); } } Ok(())}
Redirect both stdout and stderr of child process to the same file
Spawns a child process and redirectsstdout
andstderr
to the samefile. It follows the same idea asrun piped externalcommands, howeverprocess::Stdio
writes to a specified file.File::try_clone
references the same file handleforstdout
andstderr
. It will ensure that both handles write with the samecursor position.
The below recipe is equivalent to run the Unix shell commandls . oops >out.txt 2>&1
.
use std::fs::File;use std::io::Error;use std::process::{Command, Stdio};fn main() -> Result<(), Error> { let outputs = File::create("out.txt")?; let errors = outputs.try_clone()?; Command::new("ls") .args(&[".", "oops"]) .stdout(Stdio::from(outputs)) .stderr(Stdio::from(errors)) .spawn()? .wait_with_output()?; Ok(())}
Continuously process child process' outputs
InRun an external command and process stdout,processing doesn't start until externalCommand
is finished.The recipe below callsStdio::piped
to create a pipe, and readsstdout
continuously as soon as theBufReader
is updated.
The below recipe is equivalent to the Unix shell commandjournalctl | grep usb
.
use std::process::{Command, Stdio};use std::io::{BufRead, BufReader, Error, ErrorKind};fn main() -> Result<(), Error> { let stdout = Command::new("journalctl") .stdout(Stdio::piped()) .spawn()? .stdout .ok_or_else(|| Error::new(ErrorKind::Other,"Could not capture standard output."))?; let reader = BufReader::new(stdout); reader .lines() .filter_map(|line| line.ok()) .filter(|line| line.find("usb").is_some()) .for_each(|line| println!("{}", line)); Ok(())}
Read Environment Variable
Reads an environment variable viastd::env::var.
use std::env;use std::fs;use std::io::Error;fn main() -> Result<(), Error> { // read `config_path` from the environment variable `CONFIG`. // If `CONFIG` isn't set, fall back to a default config path. let config_path = env::var("CONFIG") .unwrap_or("/etc/myapp/config".to_string()); let config: String = fs::read_to_string(config_path)?; println!("Config: {}", config); Ok(())}