https://github.com/capr/die
Brazilian wax for Bash
https://github.com/capr/die
Last synced: 11 months ago
JSON representation
Brazilian wax for Bash
- Host: GitHub
- URL: https://github.com/capr/die
- Owner: capr
- License: unlicense
- Created: 2014-01-05T13:49:50.000Z (over 12 years ago)
- Default Branch: master
- Last Pushed: 2022-01-31T12:30:08.000Z (over 4 years ago)
- Last Synced: 2025-01-13T23:11:03.390Z (over 1 year ago)
- Language: Shell
- Homepage:
- Size: 12.7 KB
- Stars: 3
- Watchers: 3
- Forks: 0
- Open Issues: 0
-
Metadata Files:
- Readme: README.md
- License: LICENSE
Awesome Lists containing this project
README
## What
A set of 7 functions for flow control and progress/error reporting for shell scripts. It makes scripts **less hairy** and more illustrative of author's intent, at the same time providing a framework for allowing the user of the script to control the interaction. It has the elegance, flexibility, simplicity, expressivness, slikness, intuitiveness, and powerfullness of a Ruby web framework, without being made in Ruby even. All in 7 lines of code, for the most exigent minimalistic affectations.
This is how it works:
```bash
. die
while [ $# -gt 0 ]; do
case "$1" in
--debug) DEBUG=true ;;
--quiet) QUIET=true ;;
--yes) YES=true ;;
esac
shift
done
debug "script started" # use --debug to see the message
say "Hi" # suppress with --quiet
some_cmd || die "can't go on" # laments and exits with code 1 if the command fails
run somecmd args # use --debug to see the full command and its exit code
must somecmd args # if somecmd fails, exits showing what ran and the exit code
hold "Look at me now" # asks for a keypress; suppress with --yes or --quiet
error "nothing serious" # reports an error and continues; supress with --quiet
say "Bye" # suppress with --quiet
debug "script ended" # see this with --debug
```
## Why
Adding error checking and progress/error reporting to shell scripts makes them ugly to the point where is hard to see the bits that do essential work from the error checking/flow control ones. Encapsulating these cross-cutting concerns aside into a small vocabulary solves the problem at the expense of learning the vocabulary.
## The Code
```bash
#!/bin/sh (source it!)
# die: basic vocabulary for flow control and progress/error reporting
# v1.1 | Cosmin Apreutesei (public domain) | http://github.com/capr/die
# these functions are influenced by $QUIET, $DEBUG and $YES variables
say() { [ "$QUIET" ] || echo "$@" >&2; }
error() { say -n "ERROR: "; say "$@"; return 1; }
die() { echo -n "EXIT: " >&2; echo "$@" >&2; exit 1; }
debug() { [ -z "$DEBUG" ] || echo "$@" >&2; }
run() { debug -n "EXEC: $@ "; "$@"; local ret=$?; debug "[$ret]"; return $ret; }
must() { debug -n "MUST: $@ "; "$@"; local ret=$?; debug "[$ret]"; [ $ret = 0 ] || die "$@ [$ret]"; }
hold() { [ $# -gt 0 ] && say "$@"; [ "$YES$QUIET" ] && return; echo -n "Press ENTER to continue, or ^C to quit."; read; }
```
[source](https://raw.github.com/capr/die/master/die) | [testing unit](https://raw.github.com/capr/die/master/die-test)
## In English
**say** `...` --- echoes arguments to stderr, and only if `$QUIET` is not set
**error** `...` --- says `ERROR: ...`
**die** `...` --- says `EXIT: ...` and exits the current process
**debug** `...` --- says `...`, but only if `$DEBUG` is set
**run** _cmd_ `...` --- run a command and debug-say `EXEC: cmd ... [exit code]`
**must** _cmd_ `...` --- run a command and debug-say `MUST: cmd ... [exit code]`, but die if the command's exit code != 0
**hold** `...` --- say `...` and then ask for a key press, but only if `$YES` or `$QUIET` is not set
## Caveats
`die` and `must` can only kill the process they were executed in. This means they won't kill the script if invoked from a subprocess. This can look counterintuitive sometimes:
```bash
somevar="$(must false)"
find | must false
find | while read f; do die "somth bad happen"; done
find | { die "somth bad happen"; } #the pipe created the subprocess, not the braces
(must false)
(false || die "somth bad happen")
echo "none of these killed me"
```
Note that `$somevar` was set to `""`, since `must` complained on stderr.
Anyway, the way to fix this is to check on the exit code of the subprocess:
```bash
somevar="$(must false)" || die "subprocess failed, echo told us"
find | must false || die "subprocess failed, | tells us"
find | while read f; do die "somth bad happen"; done || die "subprocess failed, I fail"
find | { die "somth bad happen"; } || die "subprocess failed, I fail"
(must false) || die "subprocess failed"
(false || die "somth bad happen") || die "subprocess failed"
echo "can't reach here"
~~~
`hold` won't work in a subprocess that redirects the standard input -- not only that, it will eat one line of the input as well!
```bash
find | hold "I can't hold you, see?"
{ :; } | hold "Even when there's no input I still can't hold you"
~~~
## Feedback
* `cosmin.apreutesei@gmail.com`