aboutsummaryrefslogtreecommitdiff
path: root/bin/try.sh
diff options
context:
space:
mode:
Diffstat (limited to 'bin/try.sh')
-rw-r--r--bin/try.sh77
1 files changed, 77 insertions, 0 deletions
diff --git a/bin/try.sh b/bin/try.sh
new file mode 100644
index 00000000..20ccbe5f
--- /dev/null
+++ b/bin/try.sh
@@ -0,0 +1,77 @@
+# Attempt a certain number of times to perform a task, buffer stderr unless and
+# until all command attempts fail
+self=try
+
+# Parse options
+while getopts 's:n:' opt ; do
+ case $opt in
+ n)
+ attn=$OPTARG
+ ;;
+ s)
+ sleep=$OPTARG
+ ;;
+ \?)
+ printf >&2 '%s: Unknown option\n' "$self"
+ exit 2
+ ;;
+ esac
+done
+shift "$((OPTIND-1))"
+
+# Check we have at least one argument left (the command to run)
+if [ "$#" -eq 0 ] ; then
+ printf >&2 '%s: Need a command to run\n' "$self"
+ exit 2
+fi
+
+# Create a temporary directory with name in $td, and handle POSIX-ish traps to
+# remove it when the script exits.
+td=
+cleanup() {
+ [ -n "$td" ] && rm -fr -- "$td"
+ if [ "$1" != EXIT ] ; then
+ trap - "$1"
+ kill "-$1" "$$"
+ fi
+}
+for sig in EXIT HUP INT TERM ; do
+ # shellcheck disable=SC2064
+ trap "cleanup $sig" "$sig"
+done
+td=$(mktd "$self") || exit
+
+# Open a filehandle to the error buffer, just to save on file operations
+errbuff=$td/errbuff
+exec 3>"$errbuff"
+
+# Keep trying the command, writing error output to the buffer file, and exit
+# if we succeed on any of them
+attc=1
+: "${attn:=3}" "${sleep:=0}"
+while [ "$attc" -le "$attn" ] ; do
+
+ # Try running the command; if it succeeds, we're done, and any previous
+ # failures get their errors discarded
+ if "$@" 2>&3 ; then
+ exit
+
+ # If the command failed, record the exit value
+ else
+ ex=$?
+ fi
+
+ # If this isn't the last run, have a sleep
+ if [ "$attc" -lt "$attn" ] ; then
+ sleep "${sleep:=0}"
+ fi
+
+ # Increment the attempt count
+ attc=$((attc + 1))
+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
+exec 3>&-
+cat -- "$td"/errbuff >&2
+exit "$ex"