# 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();
```