diff options
-rw-r--r-- | README.markdown | 5 | ||||
-rwxr-xr-x | bin/maybe | 79 | ||||
-rwxr-xr-x | bin/try | 95 | ||||
-rw-r--r-- | man/man1/maybe.1 | 25 | ||||
-rw-r--r-- | man/man1/try.1 | 21 |
5 files changed, 225 insertions, 0 deletions
diff --git a/README.markdown b/README.markdown index b8086fe2..b03ae954 100644 --- a/README.markdown +++ b/README.markdown @@ -282,9 +282,14 @@ Scripts * `han(1)` provides a `keywordprg` for Vim's Bash script filetype that will look for `help` topics. You could use it from the shell too. It also has a brief manual. +* `maybe(1)` is like `true(1)` or `false(1)`; given a probability of success, + it exits with success or failure. Good for quick tests. * `sue(8)` execs `sudoedit(8)` as the owner of all the file arguments given, perhaps in cases where you may not necessarily have `root` `sudo(8)` privileges. +* `try(1)` repeats a command up to a given number of times until it succeeds, + only printing error output if all three attempts failed. Good for + tolerating blips or temporary failures in `cron(8)` scripts. * `vis(1)` edits executable script files in `VISPATH`, defaulting to `~/.local/bin`, for personal scripting snippets. diff --git a/bin/maybe b/bin/maybe new file mode 100755 index 00000000..2110a959 --- /dev/null +++ b/bin/maybe @@ -0,0 +1,79 @@ +#!/usr/bin/env bash + +# +# maybe(1) -- Like true(1) or false(1); exit with either success or failure +# randomly. Good for basic testing, but doesn't use precise probabilities, just +# fractions of RANDOM's limit. Exits with 2 on usage errors so you can tell the +# difference. +# +# -h gives help, -v gives you stdout specifying success or failure. +# +# Author: Tom Ryder <tom@sanctum.geek.nz> +# Copyright: 2016 +# +self=maybe + +# Print usage information +usage() { + printf '%s: usage: %s [-hv] [-d DENOMINATOR]\n' \ + "$self" "$self" +} + +# Flag for whether to print diagnostics to stdout or not +declare -i verbose +verbose=0 + +# Denominator of the probability fraction, e.g. 3 is a probability of 1/3; +# defaults to 2 +declare -i denom +denom=2 + +# Process options +while getopts 'hvd:' opt ; do + case $opt in + + # -h: Print help + h) + usage + exit 0 + ;; + + # -v: Print diagnostics to stdout + v) + verbose=1 + ;; + + # -d: Set the denominator of the probability fraction + d) + denom=$OPTARG + ;; + + # Unknown option + \?) + usage >&2 + exit 2 + ;; + esac +done +shift "$((OPTIND-1))" + +# If there are any non-option arguments or our denominator isn't a positive +# integer, we're being abused and we won't put up with it +if (($#)) || ! ((denom > 0)) ; then + usage >&2 + exit 2 +fi + +# Perform the test and print/exit appropriately +((verbose)) && printf '%s: Testing with probability 1/%u ... \n' \ + "$self" "$denom" +if ((RANDOM < 32767/denom)) ; then + ((verbose)) && printf '%s: %s\n' \ + "$self" 'Success!' + exit 0 +else + ((verbose)) && printf '%s: %s\n' \ + "$self" 'Failure!' + exit 1 +fi + diff --git a/bin/try b/bin/try new file mode 100755 index 00000000..ace12a14 --- /dev/null +++ b/bin/try @@ -0,0 +1,95 @@ +#!/usr/bin/env bash + +# +# try(1) -- Attempt a certain number of times to perform a task, stopping after +# the first success, and only print collected stderr if all the attempts +# failed. Designed for running from systems like cron(8) where blips and +# short-term failures can be ignored. +# +# -h gives help, -n sets the number of attempts (defaults to 3), -v gives you +# diagnostics on stdout. +# +self=try + +# Print usage information +usage() { + printf '%s: usage: %s [-hv] [-n ATTEMPTS] [--] COMMAND...\n' \ + "$self" "$self" +} + +# Flag for whether to print diagnostics to stdout or not +declare -i verbose +verbose=0 + +# Number of attempts +declare -i attc +attc=2 + +# Process options +while getopts 'hvn:' opt ; do + case $opt in + + # -h: Print help + h) + usage + exit 0 + ;; + + # -v: Print diagnostics to stdout + v) + verbose=1 + ;; + + # -n: Set the number of attempts + n) + attc=$OPTARG + ;; + + # Unknown option + \?) + usage >&2 + exit 2 + ;; + esac +done +shift "$((OPTIND-1))" + +# We need at least one more argument after shifting off the options +if ! (($#)) ; then + usage >&2 + exit 2 +fi + +# The command is all the remaining arguments +declare -a command +cmd=("$@") + +# Create a buffer file for the error output, and clean up the file when we exit +errbuf=$(mktemp) || exit +cleanup() { + rm -f -- "$errbuf" +} +trap cleanup EXIT + +# Keep trying the command, writing error output to the buffer file, and exit +# if we succeed on any of them +declare -i ret +for (( atti = 1 ; atti <= attc ; atti++ )) ; do + ((verbose)) && printf '%s: Attempt %u/%u to run `%s` ...\n' \ + "$self" "$atti" "$attc" "${cmd[*]}" + if "${cmd[@]}" 2>>"$errbuf" ; then + ((verbose)) && printf '%s: Success!\n' \ + "$self" + exit 0 + else + ret=$? + ((verbose)) && printf '%s: Failure!\n' \ + "$self" + fi +done + +# Attempts were exhausted, and all failed; print the error output from all of +# the failures and exit with the non-zero exit value of the most recent one +cat -- "$errbuf" >&2 +exit "$ret" + diff --git a/man/man1/maybe.1 b/man/man1/maybe.1 new file mode 100644 index 00000000..ebd622b3 --- /dev/null +++ b/man/man1/maybe.1 @@ -0,0 +1,25 @@ +.TH MAYBE 1 "November 2015" "Manual page for maybe" +.SH NAME +.B maybe +\- possibly exit with success +.SH USAGE +.B maybe [-hv] [-d DENOMINATOR] +.SH DESCRIPTION +Like true(1) or false(1), but exits with success randomly with a given +probability. Good for using in tests. Exits with 2 rather than 1 on usage +errors. +.P +This just uses integer division with Bash's special RANDOM variable, so it's +far from scientific precision. +.P +Option -h gives help, option -v turns on verbose output, option -d specifies +the denominator for the probability; defaults to 2 (i.e. roughly equal chance +of success or failure). +.P + $ maybe + $ maybe -v -d3 +.SH SEE ALSO +try(1) +.SH AUTHOR +Tom Ryder <tom@sanctum.geek.nz> + diff --git a/man/man1/try.1 b/man/man1/try.1 new file mode 100644 index 00000000..b21e69c3 --- /dev/null +++ b/man/man1/try.1 @@ -0,0 +1,21 @@ +.TH TRY 1 "November 2015" "Manual page for try" +.SH NAME +.B try +\- attempt a command up to a certain number of times until it succeeds +.SH USAGE +.B try [-hv] [-n ATTEMPTS] [--] COMMAND...' +.SH DESCRIPTION +Runs the given command up to a fixed number of times until it exits zero. If +all attempts fail, writes buffered error output from all attempts to stderr. +.P +Option -h gives help, option -v turns on verbose output, option -n specifies +the number of attempts; defaults to 3. Options may be terminated with --. The +remaining arguments are the command to run. +.P + $ try getmails + $ try -v -n3 maybe +.SH SEE ALSO +maybe(1) +.SH AUTHOR +Tom Ryder <tom@sanctum.geek.nz> + |