# run_shell - shell script written in rust. run_shell is a helper library for std::process::Command to write shell script like tasks in rust. The library only works with unix-like operation systems. ## Run command ```rust extern crate run_shell; use run_shell::*; // Run command by cmd! macro cmd!("echo Hello rust run_shell!").run().unwrap(); // Contain white space or non-alphabetical characters cmd!("echo \"%$#\"").run().unwrap(); // Pass an argument let name = "run_shell"; cmd!("echo Hello rust {}!", name).run().unwrap(); // Extract environment variable cmd!("echo HOME is $HOME").run().unwrap(); ``` ## ShellResult The return value of `ShellCommand#run()` is `ShellResult` which is `Ok(_)` only when the command successfully runs and its execution code is 0, so you can use `?` operator to check if the command successfully exits or not. ```rust extern crate run_shell; use run_shell::*; fn shell_function() -> ShellResult { cmd!("echo Command A").run()?; cmd!("echo Command B").run()?; run_shell::ok() } ``` ## Output string ShellCommand has a shorthand to obtain stdout as UTF8 string. ```rust extern crate run_shell; use run_shell::*; assert_eq!(cmd!("echo OK").stdout_utf8().unwrap(), "OK\n"); ``` ## Spawn ShellCommand has `spawn()` method which runs the command asynchronously and returns `ShellChild`. ```rust extern crate run_shell; use run_shell::*; extern crate libc; // Wait let child = cmd!("sleep 2").spawn().unwrap(); child.wait().unwrap(); // Signal let child = cmd!("sleep 2").spawn().unwrap(); let result = child.wait(); assert!(result.status().is_ok(), "Still able to obtain status"); ``` ## Thread If you would like to run a sequence of commands asynchronously, `shell::spawn` creates a thread as well as `std::thread::spawn` but it returns `ShellHandle` wrapping `std::thread::JoinHandle`. `ShellHandle#signal()` is used to send a signal to processes running on the thread. It also stops launching a new process by `ShellComamnd::run()` on that thread. ```rust extern crate run_shell; use run_shell::*; extern crate libc; let handle = run_shell::spawn(|| -> ShellResult { cmd!("sleep 3").run() }); let result = handle.join().unwrap(); assert!(result.status().is_ok(), "Still able to obtain status"); ``` ## Signal handling `trap_signal_and_wait_children()` starts watching SIGINT and SIGTERM, and waits all child processes before exiting the process when receiving these signals. The function needs to be called before launching any new thread. ```rust extern crate run_shell; use run_shell::*; run_shell::trap_signal_and_wait_children().unwrap(); ``` ## Access underlaying objects `ShellComamnd` wraps `std::process::Command` and `ShellChild` wraps `std::process::Child`. Both underlaying objects are accessible via public fields. ```rust extern crate run_shell; use run_shell::*; use std::process::Stdio; use std::io::Read; // Access std::process::Command. let mut shell_command = cmd!("echo OK"); { let command = &mut shell_command.command; command.stdout(Stdio::piped()); } // Access std::process::Child. let shell_child = shell_command.spawn().unwrap(); { let mut lock = shell_child.0.write().unwrap(); let child = &mut lock.as_mut().unwrap().child; let mut str = String::new(); child .stdout .as_mut() .unwrap() .read_to_string(&mut str) .unwrap(); } shell_child.wait().unwrap(); ```