I hate it when I have a complex bash script that I need to run and it has lots of steps in it, any one of which can fail. However, NOT re-running all the previously succeeded steps seems efficient. And in some circumstances, running any previous steps prove catastrophic.
I could just run the script and hope it works, and when it fails, fix the failing bits, while removing the already run code, but keeping the variable declarations.
Or I could source this bash script. ;)
#!/bin/bash set -o functrace set -o history set +o noclobber shopt -s extdebug [[ ${BASH_VERSINFO[0]} -lt 4 ]] && { echo "BASH Version 4 or higher required by idempotency.sh" exit 1 } idem_debug() { [[ "${DEBUG}" != "" ]] && echo "$@" } idem_is_command() { local cmd="$( echo "$1" | awk '{print $2}' )" command -v "$cmd" >/dev/null 2>&1 && return 0 [[ -z "$( which "$cmd" 2>/dev/null)" ]] && return 1 return 0 } idem_debug "idempotency using source file '${0}'" idem_dir="${0%\/*}" [[ "${idem_dir}" == "" ]] || [[ "${idem_dir}" == "$0" ]] && { idem_dir="." } idem_debug "idempotency using source dir '${idem_dir}'" idem_file="${idem_dir}/.${0/#*\/}.idempotent" idem_debug "idempotency using history file '${idem_file}'" idem_trap() { local cmd=$(history 1) idem_debug "idempotency checking command '${cmd}' subpart '${BASH_COMMAND}'" [[ "${idem_last}" == "${cmd}" ]] && { idem_debug "idempotency not re-checking subshell/pipe breakdown for '${BASH_COMMAND}'" return 0 # return ok } ! idem_is_command "${cmd}" && { idem_debug "idempotency running non-command '${cmd}'" return 0 } export idem_last="${cmd}" [[ -f "${idem_file}" ]] && grep -qF "${cmd}" ${idem_file} && { idem_debug "idempotency not running previously run command '${cmd}'" return 1 # don't run the command again } echo "${cmd}" >> ${idem_file} idem_debug "idempotency running command '${cmd}'" return 0 } trap idem_trap DEBUG
It uses the preexec hack idea from glyph, and I need to write a bunch of tests for it.