#!/usr/bin/env bash ######################################################## # Simple and fancy input & output ######################################################## which tput > /dev/null 2>&1 && [[ $(tput -T$TERM colors) -gt 8 ]] && CAN_USE_COLORS=1 || CAN_USE_COLORS=0 USE_COLORS=${USE_COLORS:-$CAN_USE_COLORS} # Icons (message prefixes) [[ "$USE_COLORS" == 1 ]] && IINFO="( i )" || IINFO='' [[ "$USE_COLORS" == 1 ]] && INOTE="( * )" || INOTE='' [[ "$USE_COLORS" == 1 ]] && IWARN="( # )" || IWARN='' [[ "$USE_COLORS" == 1 ]] && IERROR="( ! )" || IERROR='' [[ "$USE_COLORS" == 1 ]] && IFATAL="( @ )" || IFATAL='' [[ "$USE_COLORS" == 1 ]] && ISUCCESS="( ! )" || ISUCCESS='' [[ "$USE_COLORS" == 1 ]] && IASK="( ? )" || IASK='' [[ "$USE_COLORS" == 1 ]] && IDEBUG="(DBG)" || IDEBUG='' [[ "$USE_COLORS" == 1 ]] && IVRB="( + )" || IVRB='' # Text attributes [[ "$USE_COLORS" == 1 ]] && FRESET="$(tput sgr0)" || FRESET='' # Normal [[ "$USE_COLORS" == 1 ]] && FBOLD="$(tput bold)" || FBOLD='' # Bold [[ "$USE_COLORS" == 1 ]] && FDIM="$(tput dim)" || FDIM='' # Dimmed [[ "$USE_COLORS" == 1 ]] && FLINE="$(tput smul)" || FLINE='' # Underlined [[ "$USE_COLORS" == 1 ]] && FENDLINE="$(tput rmul)" || FENDLINE='' # End of underlined [[ "$USE_COLORS" == 1 ]] && FBLINK="$(tput blink)" || FBLINK='' # Blink [[ "$USE_COLORS" == 1 ]] && FREV="$(tput rev)" || FREV='' # Reversed # Text colors - normal [[ "$USE_COLORS" == 1 ]] && FBLACK="$(tput setaf 0)" || FBLACK='' # Black [[ "$USE_COLORS" == 1 ]] && FRED="$(tput setaf 1)" || FRED='' # Red [[ "$USE_COLORS" == 1 ]] && FGREEN="$(tput setaf 2)" || FGREEN='' # Green [[ "$USE_COLORS" == 1 ]] && FYELLOW="$(tput setaf 3)" || FYELLOW='' # Yellow [[ "$USE_COLORS" == 1 ]] && FBLUE="$(tput setaf 4)" || FBLUE='' # Blue [[ "$USE_COLORS" == 1 ]] && FPURPLE="$(tput setaf 5)" || FPURPLE='' # Purple [[ "$USE_COLORS" == 1 ]] && FCYAN="$(tput setaf 6)" || FCYAN='' # Cyan [[ "$USE_COLORS" == 1 ]] && FWHITE="$(tput setaf 7)" || FWHITE='' # White # Text colors - bright [[ "$USE_COLORS" == 1 ]] && FLBLACK="$(tput setaf 8)" || FLBLACK='' # Black [[ "$USE_COLORS" == 1 ]] && FLRED="$(tput setaf 9)" || FLRED='' # Red [[ "$USE_COLORS" == 1 ]] && FLGREEN="$(tput setaf 10)" || FLGREEN='' # Green [[ "$USE_COLORS" == 1 ]] && FLYELLOW="$(tput setaf 11)" || FLYELLOW='' # Yellow [[ "$USE_COLORS" == 1 ]] && FLBLUE="$(tput setaf 12)" || FLBLUE='' # Blue [[ "$USE_COLORS" == 1 ]] && FLPURPLE="$(tput setaf 13)" || FLPURPLE='' # Purple [[ "$USE_COLORS" == 1 ]] && FLCYAN="$(tput setaf 14)" || FLCYAN='' # Cyan [[ "$USE_COLORS" == 1 ]] && FLWHITE="$(tput setaf 15)" || FLWHITE='' # White # Background colors - normal [[ "$USE_COLORS" == 1 ]] && FBBLACK="$(tput setab 0)" || FBBLACK='' # Black [[ "$USE_COLORS" == 1 ]] && FBRED="$(tput setab 1)" || FBRED='' # Red [[ "$USE_COLORS" == 1 ]] && FBGREEN="$(tput setab 2)" || FBGREEN='' # Green [[ "$USE_COLORS" == 1 ]] && FBYELLOW="$(tput setab 3)" || FBYELLOW='' # Yellow [[ "$USE_COLORS" == 1 ]] && FBBLUE="$(tput setab 4)" || FBBLUE='' # Blue [[ "$USE_COLORS" == 1 ]] && FBPURPLE="$(tput setab 5)" || FBPURPLE='' # Purple [[ "$USE_COLORS" == 1 ]] && FBCYAN="$(tput setab 6)" || FBCYAN='' # Cyan [[ "$USE_COLORS" == 1 ]] && FBWHITE="$(tput setab 7)" || FBWHITE='' # White # Background colors - bright [[ "$USE_COLORS" == 1 ]] && FBLBLACK="$(tput setab 8)" || FBLBLACK='' # Black [[ "$USE_COLORS" == 1 ]] && FBLRED="$(tput setab 9)" || FBLRED='' # Red [[ "$USE_COLORS" == 1 ]] && FBLGREEN="$(tput setab 10)" || FBLGREEN='' # Green [[ "$USE_COLORS" == 1 ]] && FBLYELLOW="$(tput setab 11)" || FBLYELLOW='' # Yellow [[ "$USE_COLORS" == 1 ]] && FBLBLUE="$(tput setab 12)" || FBLBLUE='' # Blue [[ "$USE_COLORS" == 1 ]] && FBLPURPLE="$(tput setab 13)" || FBLPURPLE='' # Purple [[ "$USE_COLORS" == 1 ]] && FBLCYAN="$(tput setab 14)" || FBLCYAN='' # Cyan [[ "$USE_COLORS" == 1 ]] && FBLWHITE="$(tput setab 15)" || FBLWHITE='' # White now() { echo "[$(date +'%H:%M:%S')] " } ask() { IFS= read -rp "$(print ${FBOLD}${FBBLUE}${FWHITE}${IASK}${FRESET}\ ${FBOLD}$1 ): " $2 } print() { # if [ -n "$SPINNER_PID" ] && ps -p $SPINNER_PID > /dev/null; then kill $SPINNER_PID > /dev/null; fi echo -e "$*${FRESET}" } link() { echo -e "\e]8;;$2\a$1\e]8;;\a" } debug() { if [ "$2" ]; then print "${FDIM}${FBOLD}${FRESET}${FDIM}$(now)${IDEBUG} ${FUNCNAME[1]:-?}():${BASH_LINENO:-?}\t$1 " >&2 else print "${FDIM}${FBOLD}${FRESET}${FDIM}$(now)${IDEBUG} $1 " >&2 fi } var_dump() { debug "$1 = ${!1}" } print_stacktrace() { STACK="" local i local stack_size=${#FUNCNAME[@]} debug "Callstack:" # for (( i=$stack_size-1; i>=1; i-- )); do for (( i=1; i<$stack_size; i++ )); do local func="${FUNCNAME[$i]}" [ x$func = x ] && func=MAIN local linen="${BASH_LINENO[$(( i - 1 ))]}" local src="${BASH_SOURCE[$i]}" [ x"$src" = x ] && src=non_file_source debug " at $func $src:$linen" done } verbose() { print "${FBOLD}$(now)${IVRB}${FRESET}${FYELLOW} $1 " } info() { print "${FBOLD}$(now)${FWHITE}${FBLBLUE}${IINFO}${FRESET}${FWHITE} $1 " } note() { print "${FBOLD}$(now)${FDIM}${FWHITE}${INOTE}${FRESET} $1 " } success() { print "${FBOLD}$(now)${FBGREEN}${FWHITE}${ISUCCESS}${FRESET}$FGREEN $1 " } warn() { print "${FBOLD}$(now)${FBYELLOW}${FBLACK}${IWARN}${FRESET}${FYELLOW} Warning:${FRESET} $1 " } error() { print "${FBOLD}$(now)${FBLRED}${FWHITE}${IERROR} Error: ${FRESET}${FLRED} $1 " >&2 } fatal() { print "${FBOLD}$(now)${FBRED}${FWHITE}${IFATAL} FATAL: $1 " >&2 print_stacktrace } die() { error "${1:-halted}" exit ${2:-255} } # var='test var_dump' # var_dump var # debug 'test debug' # verbose 'test verbose' # info 'test info' # note 'test note' # success 'test success' # warn 'test warn' # error 'test error' # fatal 'test fatal' # die 'test die' # experiments ============================================================================== # spinner() { # local frames=('⠋' '⠙' '⠹' '⠸' '⠼' '⠴' '⠦' '⠧' '⠇' '⠏') # local spin_i=0 # local interval=0.1 # printf "\e[?25l" # local color="${FGREEN}" # while true; do # printf "\r ${color}%s${CL}" "${frames[spin_i]}" # spin_i=$(( (spin_i + 1) % ${#frames[@]} )) # sleep "$interval" # done # } # echo "lorem ipsum dolor sit amet" # spinner & # SPINNER_PID=$! # =========== # https://unix.stackexchange.com/a/269085 # https://en.wikipedia.org/wiki/ANSI_escape_code#8-bit # https://linuxcommand.org/lc3_adv_tput.php # https://gist.github.com/nowmilano/4055d6df5b6e4ea87c5a72dc2d604193 # https://gist.github.com/nick3499/402a6d7dccd474f2bdb679f4311b1238 # https://gist.github.com/connorjan/2b02126868157c2b69f9aa0a052cdc86 # tput setaf 0 # echo "BLACK FOREGROUND" # tput setaf 1 # echo "RED FOREGROUND" # tput setaf 2 # echo "GREEN FOREGROUND" # tput setaf 3 # echo "YELLOW FOREGROUND" # tput setaf 4 # echo "BLUE FOREGROUND" # tput setaf 5 # echo "MAGENTA FOREGROUND" # tput setaf 6 # echo "CYAN FOREGROUND" # tput setaf 7 # echo "WHITE FOREGROUND" # tput reset # =========== # =========== # tohex(){ # dec=$(($1%256)) ### input must be a number in range 0-255. # if [ "$dec" -lt "16" ]; then # bas=$(( dec%16 )) # mul=128 # [ "$bas" -eq "7" ] && mul=192 # [ "$bas" -eq "8" ] && bas=7 # [ "$bas" -gt "8" ] && mul=255 # a="$(( (bas&1) *mul ))" # b="$(( ((bas&2)>>1)*mul ))" # c="$(( ((bas&4)>>2)*mul ))" # printf 'dec= %3s basic= #%02x%02x%02x\n' "$dec" "$a" "$b" "$c" # elif [ "$dec" -gt 15 ] && [ "$dec" -lt 232 ]; then # b=$(( (dec-16)%6 )); b=$(( b==0?0: b*40 + 55 )) # g=$(( (dec-16)/6%6)); g=$(( g==0?0: g*40 + 55 )) # r=$(( (dec-16)/36 )); r=$(( r==0?0: r*40 + 55 )) # printf 'dec= %3s color= #%02x%02x%02x\n' "$dec" "$r" "$g" "$b" # else # gray=$(( (dec-232)*10+8 )) # printf 'dec= %3s gray= #%02x%02x%02x\n' "$dec" "$gray" "$gray" "$gray" # fi # } # for i in $(seq 0 255); do # tohex ${i} # done # =========== # fromhex(){ # hex=${1#"#"} # r=$(printf '0x%0.2s' "$hex") # g=$(printf '0x%0.2s' ${hex#??}) # b=$(printf '0x%0.2s' ${hex#????}) # printf '%03d' "$(( (r<75?0:(r-35)/40)*6*6 + # (g<75?0:(g-35)/40)*6 + # (b<75?0:(b-35)/40) + 16 ))" # } # fromhex 00fc7b # =========== # mode2header(){ # #### For 16 Million colors use \e[0;38;2;R;G;Bm each RGB is {0..255} # printf '\e[mR\n' # reset the colors. # printf '\n\e[m%59s\n' "Some samples of colors for r;g;b. Each one may be 000..255" # printf '\e[m%59s\n' "for the ansi option: \e[0;38;2;r;g;bm or \e[0;48;2;r;g;bm :" # } # mode2colors(){ # # foreground or background (only 3 or 4 are accepted) # local fb="$1" # [[ $fb != 3 ]] && fb=4 # local samples=(0 63 127 191 255) # for r in "${samples[@]}"; do # for g in "${samples[@]}"; do # for b in "${samples[@]}"; do # printf '\e[0;%s8;2;%s;%s;%sm%03d;%03d;%03d ' "$fb" "$r" "$g" "$b" "$r" "$g" "$b" # done; printf '\e[m\n' # done; printf '\e[m' # done; printf '\e[mReset\n' # } # mode2header # mode2colors 3 # mode2colors 4 # =========== # printf '\e[48;5;%dm ' {0..255}; printf '\e[0m \n' # for r in {200..255..5}; do # fb=4 # g=1 # b=1 # printf '\e[0;%s8;2;%s;%s;%sm ' "$fb" "$r" "$g" "$b" # done # echo # =========== # color(){ # for c; do # printf '\e[48;5;%dm%03d' $c $c # done # printf '\e[0m \n' # } # IFS=$' \t\n' # color {0..15} # for ((i=0;i<6;i++)); do # color $(seq $((i*36+16)) $((i*36+51))) # done # color {232..255} # =========== # for ((i=0; i<256; i++)) ;do # echo -n ' ' # tput setab $i # tput setaf $(( ( (i>231&&i<244 ) || ( (i<17)&& (i%8<2)) || # (i>16&&i<232)&& ((i-16)%6 <(i<100?3:2) ) && ((i-16)%36<15) )?7:16)) # printf " C %03d " $i # tput op # (( ((i<16||i>231) && ((i+1)%8==0)) || ((i>16&&i<232)&& ((i-15)%6==0)) )) && # printf "\n" '' # done # =========== # echo "tput character test" # echo "===================" # echo # tput bold; echo "This text has the bold attribute."; tput sgr0 # tput smul; echo "This text is underlined (smul)."; tput rmul # # Most terminal emulators do not support blinking text (though xterm # # does) because blinking text is considered to be in bad taste ;-) # tput blink; echo "This text is blinking (blink)."; tput sgr0 # tput rev; echo "This text has the reverse attribute"; tput sgr0 # # Standout mode is reverse on many terminals, bold on others. # tput smso; echo "This text is in standout mode (smso)."; tput rmso # tput sgr0 # echo # experiments ============================================================================== # function delay_spinner(){ # ## # ## Usage: # ## # ## $ long-running-command & # ## $ delay_spinner " Please wait msg..." # ## # ## Spinner exists when long-running-command completes # ## # local PROGRESSTXT # if [ ! "$1" ]; then # PROGRESSTXT=" Please wait..." # else # PROGRESSTXT="$1" # fi # # visual progress marker function # # http://stackoverflow.com/users/2869509/wizurd # # vars # local pid=$! # local delay=0.1 # local spinstr='|/-\' # echo -e "\n\n" # while [ "$(ps a | awk '{print $1}' | grep $pid)" ]; do # local temp=${spinstr#?} # printf "\r$PROGRESSTXT[%c] " "$spinstr" # local spinstr=$temp${spinstr%"$temp"} # sleep $delay # printf "\b\b\b\b\b\b" # done # printf -- '\n\n' # # # # <-- end function ec2cli_spinner --> # # # } # sleep 10 && echo 'test' & # delay_spinner "Please wait msg..."