Внешняя команда
Запуск внешне команды и обработка стандартного вывода
Запускает git log --oneline
как внешнюю команду Command
и проверяет её вывод Output
используя Regex
, чтобы получить хеш и сообщение о последних 5 коммитах.
#[macro_use] extern crate error_chain; extern crate regex; use std::process::Command; use regex::Regex; error_chain!{ foreign_links { Io(std::io::Error); Regex(regex::Error); Utf8(std::string::FromUtf8Error); } } #[derive(PartialEq, Default, Clone, Debug)] struct Commit { hash: String, message: String, } fn main() -> Result<()> { let output = Command::new("git").arg("log").arg("--oneline").output()?; if !output.status.success() { bail!("Command executed with failing error code"); } let pattern = Regex::new(r"(?x) ([0-9a-fA-F]+) # commit hash (.*) # The commit message")?; String::from_utf8(output.stdout)? .lines() .filter_map(|line| pattern.captures(line)) .map(|cap| { Commit { hash: cap[1].to_string(), message: cap[2].trim().to_string(), } }) .take(5) .for_each(|x| println!("{:?}", x)); Ok(()) }
Запуск внешней команды, передав ей stdin, и проверка кода ошибки
Открывает интерпретатор python
с помощью внешней команды Command
и передаёт ему инструкции языка python для выполнения. Вывод Output
оператора затем анализируется.
#[macro_use] extern crate error_chain; use std::collections::HashSet; use std::io::Write; use std::process::{Command, Stdio}; error_chain!{ errors { CmdError } foreign_links { Io(std::io::Error); Utf8(std::string::FromUtf8Error); } } 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("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)?; bail!("External command failed:\n {}", err) } }
Запуск внешние команды цепочками
Показывает до десяти самых больших файлов и подкаталогов в текущем рабочем каталоге. Это эквивалентно запуску: du -ah . | sort -hr | head -n 10
.
Command
-ы представляют процесс. Вывод дочернего процесса захватывается с помощью Stdio::piped
между родительским и дочерним процессами.
#[macro_use] extern crate error_chain; use std::process::{Command, Stdio}; error_chain! { foreign_links { Io(std::io::Error); Utf8(std::string::FromUtf8Error); } } 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(()) }
Перенаправить stdout и stderr дочернего процесса в один файл
Создаёт дочерний процесс и перенаправляет stdout
и stderr
в один и тот же файл. Рецепт следует той же идее, что и запуск внешних команд цепочкой , однако process::Stdio
записывает в указанный файл. File::try_clone
ссылается на один и тот же дескриптор файла для stdout
и stderr
. Это гарантирует, что оба дескриптора пишут с одинаковой позиции курсора.
Приведённый ниже рецепт эквивалентен запуску команды оболочки Unix ls . 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(()) }
Постоянная обработка вывода дочернего процесса
В разделе Выполнить внешнюю команду и обработать её стандартный вывод обработка не начинается до тех пор, пока не завершится внешняя Command
. Приведённый ниже рецепт вызывает Stdio::piped
для создания канала и непрерывно читает стандартный stdout
как только обновляется BufReader
.
Этот рецепт эквивалентен команде оболочки Unix journalctl | 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(()) }