#!/usr/bin/env sh GETOPT_BIN=$IN_GETOPT_BIN GETOPT_BIN=${GETOPT_BIN:-getopt} __sleep_amount() { if [ -n "$constant_sleep" ]; then sleep_time=$constant_sleep else #TODO: check for awk #TODO: check if user would rather use one of the other possible dependencies: python, ruby, bc, dc sleep_time=$(awk "BEGIN {t = $min_sleep * $((1 << (_retry_attempts - 1))); print (t > $max_sleep ? $max_sleep : t)}") fi } __log_out() { echo "$1" 1>&2 } # Parameters: max_tries min_sleep max_sleep constant_sleep fail_script EXECUTION_COMMAND retry() { _retry_max_tries="$1" shift _retry_min_sleep="$1" shift _retry_max_sleep="$1" shift _retry_constant_sleep="$1" shift _retry_fail_script="$1" shift if [ -n "$VERBOSE" ]; then __log_out "Retry Parameters: max_tries=$_retry_max_tries min_sleep=$_retry_min_sleep max_sleep=$_retry_max_sleep constant_sleep=$_retry_constant_sleep" if [ -n "$_retry_fail_script" ]; then __log_out "Fail script: $_retry_fail_script"; fi __log_out "" __log_out "Execution Command: $*" __log_out "" fi _retry_attempts=0 _retry_return_code=1 while [ "$_retry_return_code" -ne 0 ] && [ "$_retry_attempts" -le "$_retry_max_tries" ]; do if [ $_retry_attempts -gt 0 ]; then __sleep_amount __log_out "Before retry #$_retry_attempts: sleeping $sleep_time seconds" sleep "$sleep_time" fi P="$1" #for param in "${@:2}"; do P="$P '$param'"; done #TODO: replace single quotes in each arg with '"'"' ? export RETRY_ATTEMPT=$_retry_attempts sh -c "$P" _retry_return_code=$? #__log_out "Process returned $_retry_return_code on attempt $_retry_attempts" if [ $_retry_return_code -eq 127 ]; then # command not found exit $_retry_return_code elif [ $_retry_return_code -ne 0 ]; then _retry_attempts=$((_retry_attempts + 1)) fi done if [ "$_retry_attempts" -gt "$_retry_max_tries" ]; then if [ -n "$_retry_fail_script" ]; then __log_out "Retries exhausted, running fail script" eval "$_retry_fail_script" else __log_out "Retries exhausted" fi fi exit $_retry_return_code } help() { _help_retry=$(basename "$0") cat </dev/null if [ $? -ne 4 ]; then echo "I’m sorry, 'getopt --test' failed in this environment. Please load GNU getopt." exit 1 fi OPTIONS=vt:s:m:x:f: LONGOPTIONS=verbose,tries:,sleep:,min:,max:,fail: PARSED=$($GETOPT_BIN --options="$OPTIONS" --longoptions="$LONGOPTIONS" --name "$0" -- "$@") # shellcheck disable=SC2181 if [ $? -ne 0 ]; then # e.g. $? == 1 # then getopt has complained about wrong arguments to stdout exit 2 fi # read getopt’s output this way to handle the quoting right: eval set -- "$PARSED" max_tries=10 min_sleep=0.3 max_sleep=60.0 constant_sleep= fail_script= # now enjoy the options in order and nicely split until we see -- while true; do case "$1" in -v | --verbose) VERBOSE=true shift ;; -t | --tries) max_tries="$2" shift 2 ;; -s | --sleep) constant_sleep="$2" shift 2 ;; -m | --min) min_sleep="$2" shift 2 ;; -x | --max) max_sleep="$2" shift 2 ;; -f | --fail) fail_script="$2" shift 2 ;; --) shift break ;; *) echo "Programming error" exit 3 ;; esac done retry "$max_tries" "$min_sleep" "$max_sleep" "$constant_sleep" "$fail_script" "$@"