# Rust shell - shell script written in rust.
This is not an officially supported Google product
Rust 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
`run!` macro creates a ShellCommand instance which you can run by `run()`
method.
```
#[macro_use] extern crate shell;
// Run command by cmd! macro
cmd!("echo Hello rust shell!").run().unwrap();
// Contain white space or non-alphabetical characters
cmd!("echo \"%$#\"").run().unwrap();
// Pass an argument
let name = "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.
```
#[macro_use] extern crate shell;
use shell::ShellResult;
fn shell_function() -> ShellResult {
cmd!("echo Command A").run()?;
cmd!("echo Command B").run()?;
shell::ok()
}
```
## Output string
ShellCommand has a shorthand to obtain stdout as UTF8 string.
```
#[macro_use] extern crate shell;
assert_eq!(cmd!("echo OK").stdout_utf8().unwrap(), "OK\n");
```
## Spawn
ShellCommand has `spawn()` method which runs the command asynchronously and
returns `ShellChild`.
```
#[macro_use] extern crate shell;
extern crate libc;
use shell::ShellResultExt;
// Wait
let child = cmd!("sleep 2").spawn().unwrap();
child.wait().unwrap();
// Signal
let child = cmd!("sleep 2").spawn().unwrap();
child.signal(libc::SIGINT);
let result = child.wait();
assert!(result.is_err(), "Should be error as it exits with a signal");
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.
```
#[macro_use] extern crate shell;
extern crate libc;
use shell::ShellResult;
use shell::ShellResultExt;
});
handle.signal(libc::SIGINT);
let result = handle.join().unwrap();
assert!(result.is_err(), "Should be error as it exits with a signal");
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.
```
extern crate shell;
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.
```
#[macro_use] extern crate shell;
use std::process::Stdio;
use std::io::Read;
// Access std::process::Command.
let mut shell_command = cmd!("echo OK");
{
let mut 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 mut child = &mut lock.as_mut().unwrap().child;
let mut str = String::new();
child.stdout.as_mut().unwrap().read_to_string(&mut str);
}
shell_child.wait().unwrap();
```
## License
Apatch 2 License