Code

setup_log="$(mktemp -t setup_logXXX)"
red="\033[1;31m"
green="\033[1;32m"
cyan="\033[0;36m"
normal="\033[0m"

spin() {
    local i=0
    local sp="/-\|"
    local n=${#sp}
    printf " "
    sleep 0.2
    while true; do
        printf "\b${cyan}%s${normal}" "${sp:i++%n:1}"
        sleep 0.2
    done
}

log() {
    exec 3>&1 4>&2
    trap 'exec 2>&4 1>&3' 0 1 2 3
    exec 1>>"$setup_log" 2>&1
    echo -e "\n${cyan}${1}${normal}\n"
}

run_step() {
    local msg="$1"
    local func="$2"
    local pos
    IFS='[;' read -p $'\e[6n' -d R -a pos -rs
    local current_row=${pos[1]}
    local current_col=${pos[2]}
    printf "${cyan}${msg}${normal}\033[${current_row};50H"
    spin &
    spinpid=$!
    trap 'kill $spinpid' SIGTERM SIGKILL
    ${func} "${msg}" &>/dev/null
    if [[ $? -eq 0 ]]; then
        kill ${spinpid}
        printf "\b \t\t${cyan}[Done]${normal}\n"
    else
        kill ${spinpid}
        printf "\b \t\t${red}[Failed]${normal}\n"
        printf "\n${red}Sorry! ${msg} went wrong. See full log at ${setup_log} ${normal}\n\n"
        exit 1
    fi
}

Usage

#!/bin/bash

setup_log="$(mktemp -t setup_logXXX)"
red="\033[1;31m"
green="\033[1;32m"
cyan="\033[0;36m"
normal="\033[0m"

spin() {
    .
    .
    .
}

log() {
    .
    .
    .
}

run_step() {
    .
    .
    .
}

hack_nasa_with_html() {
    log "$1"
    sleep 3
}

function_that_will_fail() {
    log "$1"
    sleep 2
    return 1
}

run_step "Hacking NASA with HTML" "hack_nasa_with_html"
run_step "Running function that will fail" "function_that_will_fail"

exit 0

Examples

Run Step