#!/bin/sh set -eu usage() { cat <<-'EOF' Usage: until [-m MAX] [-n SECONDS] COMMAND... until -h EOF } help() { cat <<-'EOF' Options: -n SECONDS the amount of seconds to sleep between attempts (default: 5) -m MAX the maximum number of attempts (default: unlimited) -h, --help show this message COMMAND the shell command to be executed Runs COMMAND until it eventually succeeds, trying atmost MAX times. Sleep SECONDS between attempts. Examples: Try flaky build until it succeeds: $ until guix home build home.scm Try atmost 10 timex to build until a new version is successfull, waiting 30 seconds between attempts: $ until -m 10 -n 30 -- x git pull AND make EOF } for flag in "$@"; do case "$flag" in (--) break ;; (--help) usage help exit ;; (*) ;; esac done _SECONDS=5 while getopts 'm:n:h' flag; do case "$flag" in (m) MAX="$OPTARG" ;; (n) _SECONDS="$OPTARG" ;; (h) usage help exit ;; (*) usage >&2 exit 2 ;; esac done shift $((OPTIND - 1)) ATTEMPT=1 while true; do printf 'Attempt %s.\n' "$ATTEMPT" >&2 ATTEMPT=$((ATTEMPT + 1)) if "$@"; then break fi if [ -n "${MAX:-}" ] && [ "$ATTEMPT" -gt "$MAX" ]; then printf 'Maximum number of attempts reached: %s.\n' "$MAX" >&2 exit 1 fi sleep "$_SECONDS" done