#!/bin/bash # pyr0ball script functions library # Initial Vars functionsrev=1.1.3 scriptname="${0##*/}" rundir="${0%/*}" rundir_absolute=$(cd `dirname $0` && pwd) runuser="$(whoami)" pretty_date="$(date +%Y-%m-%d_%H-%M-%S)" short_date="$(date +%Y-%m-%d)" # Escape characters (if your shell uses a different one, you can modify it here) # By default this is using the usual bash escape code ESC=$( printf '\033') # Detect OS type case $OSTYPE in linux-gnu* ) ESC=$( printf '\033') ;; darwin* ) ESC=$( printf '\e') ;; cygwin ) ESC=$( printf '\033') ;; msys ) ESC=$( printf '\033') ;; esac # Utilities (Setting up colors and bounding boxes) # boxtype changes what borders are used for the boxborder functions. # options are "single" "double" "char" # for the "char" option, change the "borderchar" variable to # whichever unicode character you wish to use # boxtype="${boxtype:-single}" # Sets default 'single' if not already set # borderchar="${borderchar:-#}" # Sets default '#' if not already set boxtype="norm" # Sets default 'single' if not already set borderchar="#" # Sets default '#' if not already set # Colorization options if [[ "$TERM" != "linux" ]] ; then red=$(echo -e "${ESC}[38;5;1m") # red grn=$(echo -e "${ESC}[38;5;2m") # green ylw=$(echo -e "${ESC}[38;5;3m") # yellow blu=$(echo -e "${ESC}[38;5;27m") # blue lbl=$(echo -e "${ESC}[38;5;69m") # light blue mag=$(echo -e "${ESC}[38;5;5m") # magenta cyn=$(echo -e "${ESC}[38;5;6m") # cyan pur=$(echo -e "${ESC}[38;5;135m") # purple ong=$(echo -e "${ESC}[38;5;166m") # orange lyl=$(echo -e "${ESC}[38;5;228m") # light yellow lrd=$(echo -e "${ESC}[38;5;196m") # light red gry=$(echo -e "${ESC}[38;5;240m") # Grey norm=$(echo -e "${ESC}[39m") # default/normal # bld=$(echo -e "${ESC}[1m") # bold unb=$(echo -e "${ESC}[21m") # un-bold dim=$(echo -e "${ESC}[2m") # dim und=$(echo -e "${ESC}[22m") # un-dim unl=$(echo -e "${ESC}[4m") # underline nln=$(echo -e "${ESC}[24") # not-underline blk=$(echo -e "${ESC}[5") # blinking unbl=$(echo -e "${ESC}[25") # stop blinking inv=$(echo -e "${ESC}[7m") # invert rsinv=$(echo -e "${ESC}[27") # reset http://www.endmemo.com/unicode/unicodeconverter.phpnvert hid=$(echo -e "${ESC}[8") # hidden unh=$(echo -e "${ESC}[28") # unhide dfl=$(echo -e "${ESC}[0m") # restore default fi # Extra Unicode Character Manipulation case $OSTYPE in linux-gnu* ) return_arrow=$(echo -e "\u2BAC") enter_arrow=$(echo -e "\u21B5") green_check=${grn}$(echo -e "\u2714")${dfl} red_x=${lrd}$(echo -e "\u00D7")${dfl} selected_opt=$(echo -e "\u25C9") deselected_opt=$(echo -e "\u25CE") ;; darwin* ) return_arrow=$(echo -e "⮬") enter_arrow=$(echo -e "↵") green_check=${grn}$(echo -e "✔")${dfl} red_x=${lrd}$(echo -e "×")${dfl} selected_opt=$(echo -e "◉") deselected_opt=$(echo -e "◎") ;; cygwin ) return_arrow=$(echo -e "\u2BAC") enter_arrow=$(echo -e "\u21B5") green_check=${grn}$(echo -e "\u2714")${dfl} red_x=${lrd}$(echo -e "\u00D7")${dfl} selected_opt=$(echo -e "\u25C9") deselected_opt=$(echo -e "\u25CE") ;; msys ) return_arrow=$(echo -e "\u2BAC") enter_arrow=$(echo -e "\u21B5") green_check=${grn}$(echo -e "\u2714")${dfl} red_x=${lrd}$(echo -e "\u00D7")${dfl} selected_opt=$(echo -e "\u25C9") deselected_opt=$(echo -e "\u25CE") ;; esac # For drawing pretty boxes terminal_width=$(tput cols) if [ $terminal_width -le 81 ] ; then BOXWIDTH=$((terminal_width - 1)) else BOXWIDTH=80 fi # Box Drawing characters case $OSTYPE in linux-gnu* ) light_h=$(echo -e "\u2500") norm_h=$(echo -e "\u2501") double_h=$(echo -e "\u2550") light_v=$(echo -e "\u2502") norm_v=$(echo -e "\u2503") double_v=$(echo -e "\u2551") ;; darwin* ) light_h=$(echo -e "─") norm_h=$(echo -e "━") double_h=$(echo -e "═") light_v=$(echo -e "│") norm_v=$(echo -e "┃") double_v=$(echo -e "║") ;; cygwin ) light_h=$(echo -e "\u2500") norm_h=$(echo -e "\u2501") double_h=$(echo -e "\u2550") light_v=$(echo -e "\u2502") norm_v=$(echo -e "\u2503") double_v=$(echo -e "\u2551") ;; msys ) light_h=$(echo -e "\u2500") norm_h=$(echo -e "\u2501") double_h=$(echo -e "\u2550") light_v=$(echo -e "\u2502") norm_v=$(echo -e "\u2503") double_v=$(echo -e "\u2551") ;; esac # Box border type single-line box-norm(){ # ---------------------------------------# case $OSTYPE in linux-gnu* ) top_border=${norm_h} bottom_border=${norm_h} left_border=${norm_v} right_border=${norm_v} left_top_border=$(echo -e "\u250f") right_top_border=$(echo -e "\u2513") left_bottom_border=$(echo -e "\u2517") right_bottom_border=$(echo -e "\u251b") box_break_line=$(echo -e "\u25AB") ;; darwin* ) top_border=${norm_h} bottom_border=${norm_h} left_border=${norm_v} right_border=${norm_v} left_top_border=$(echo -e "┏") right_top_border=$(echo -e "┓") left_bottom_border=$(echo -e "┗") right_bottom_border=$(echo -e "┛") box_break_line=$(echo -e "▫") ;; cygwin ) top_border=${norm_h} bottom_border=${norm_h} left_border=${norm_v} right_border=${norm_v} left_top_border=$(echo -e "\u250f") right_top_border=$(echo -e "\u2513") left_bottom_border=$(echo -e "\u2517") right_bottom_border=$(echo -e "\u251b") box_break_line=$(echo -e "\u25AB") ;; msys ) top_border=${norm_h} bottom_border=${norm_h} left_border=${norm_v} right_border=${norm_v} left_top_border=$(echo -e "\u250f") right_top_border=$(echo -e "\u2513") left_bottom_border=$(echo -e "\u2517") right_bottom_border=$(echo -e "\u251b") box_break_line=$(echo -e "\u25AB") ;; esac # ---------------------------------------# } # Box border type double-line box-double(){ # ---------------------------------------# case $OSTYPE in linux-gnu* ) top_border=${double_h} bottom_border=${double_h} left_border=${double_v} right_border=${double_v} left_top_border=$(echo -e "\u2554") right_top_border=$(echo -e "\u2557") left_bottom_border=$(echo -e "\u255A") right_bottom_border=$(echo -e "\u255D") box_break_line=$(echo -e "\u25AB") ;; darwin* ) top_border=${double_h} bottom_border=${double_h} left_border=${double_v} right_border=${double_v} left_top_border=$(echo -e "╔") right_top_border=$(echo -e "╗") left_bottom_border=$(echo -e "╚") right_bottom_border=$(echo -e "╝") box_break_line=$(echo -e "▫") ;; cygwin ) top_border=${double_h} bottom_border=${double_h} left_border=${double_v} right_border=${double_v} left_top_border=$(echo -e "\u2554") right_top_border=$(echo -e "\u2557") left_bottom_border=$(echo -e "\u255A") right_bottom_border=$(echo -e "\u255D") box_break_line=$(echo -e "\u25AB") ;; msys ) top_border=${double_h} bottom_border=${double_h} left_border=${double_v} right_border=${double_v} left_top_border=$(echo -e "\u2554") right_top_border=$(echo -e "\u2557") left_bottom_border=$(echo -e "\u255A") right_bottom_border=$(echo -e "\u255D") box_break_line=$(echo -e "\u25AB") ;; esac # ---------------------------------------# } # Box border type thick-line box-heavy(){ # ---------------------------------------# case $OSTYPE in linux-gnu* ) top_border=$(echo -e "\u2580") bottom_border=$(echo -e "\u2584") left_border=$(echo -e "\u258C") right_border=$(echo -e "\u2590") left_top_border=$(echo -e "\u259B") right_top_border=$(echo -e "\u259C") left_bottom_border=$(echo -e "\u2599") right_bottom_border=$(echo -e "\u259F") box_break_line=$(echo -e "\u25AC") ;; darwin* ) top_border=$(echo -e "▀") bottom_border=$(echo -e "▄") left_border=$(echo -e "▌") right_border=$(echo -e "▐") left_top_border=$(echo -e "▛") right_top_border=$(echo -e "▜") left_bottom_border=$(echo -e "▙") right_bottom_border=$(echo -e "▟") box_break_line=$(echo -e "▫") ;; cygwin ) top_border=$(echo -e "\u2580") bottom_border=$(echo -e "\u2584") left_border=$(echo -e "\u258C") right_border=$(echo -e "\u2590") left_top_border=$(echo -e "\u259B") right_top_border=$(echo -e "\u259C") left_bottom_border=$(echo -e "\u2599") right_bottom_border=$(echo -e "\u259F") box_break_line=$(echo -e "\u25AC") ;; msys ) top_border=$(echo -e "\u2580") bottom_border=$(echo -e "\u2584") left_border=$(echo -e "\u258C") right_border=$(echo -e "\u2590") left_top_border=$(echo -e "\u259B") right_top_border=$(echo -e "\u259C") left_bottom_border=$(echo -e "\u2599") right_bottom_border=$(echo -e "\u259F") box_break_line=$(echo -e "\u25AC") ;; esac # ---------------------------------------# } # Box border type thin-line box-light(){ # ---------------------------------------# #top_border=$(echo -e '\u23BA') case $OSTYPE in linux-gnu* ) top_border=${light_h} bottom_border=${light_h} left_border=${light_v} right_border=${light_v} left_top_border=$(echo -e "\u23BE") right_top_border=$(echo -e "\u23CB") left_bottom_border=$(echo -e "\u23BF") right_bottom_border=$(echo -e "\u23CC") box_break_line=$(echo -e "\u23AF") ;; darwin* ) top_border=${light_h} bottom_border=${light_h} left_border=${light_v} right_border=${light_v} left_top_border=$(echo -e "⎾") right_top_border=$(echo -e "⏋") left_bottom_border=$(echo -e "⎿") right_bottom_border=$(echo -e "⏌") box_break_line=$(echo -e "⎯") ;; cygwin ) top_border=${light_h} bottom_border=${light_h} left_border=${light_v} right_border=${light_v} left_top_border=$(echo -e "\u23BE") right_top_border=$(echo -e "\u23CB") left_bottom_border=$(echo -e "\u23BF") right_bottom_border=$(echo -e "\u23CC") box_break_line=$(echo -e "\u23AF") ;; msys ) top_border=${light_h} bottom_border=${light_h} left_border=${light_v} right_border=${light_v} left_top_border=$(echo -e "\u23BE") right_top_border=$(echo -e "\u23CB") left_bottom_border=$(echo -e "\u23BF") right_bottom_border=$(echo -e "\u23CC") box_break_line=$(echo -e "\u23AF") ;; esac # ---------------------------------------# } box-rounded(){ # ---------------------------------------# case $OSTYPE in linux-gnu* ) top_border=${light_h} bottom_border=${light_h} left_border=${light_v} right_border=${light_v} left_top_border=$(echo -e "\u256D") right_top_border=$(echo -e "\u256E") left_bottom_border=$(echo -e "\u2570") right_bottom_border=$(echo -e "\u256F") box_break_line=$(echo -e "\u25A2") ;; darwin* ) top_border=${light_h} bottom_border=${light_h} left_border=${light_v} right_border=${light_v} left_top_border=$(echo -e "╭") right_top_border=$(echo -e "╮") left_bottom_border=$(echo -e "╰") right_bottom_border=$(echo -e "╯") box_break_line=$(echo -e "▢") ;; cygwin ) top_border=${light_h} bottom_border=${light_h} left_border=${light_v} right_border=${light_v} left_top_border=$(echo -e "\u256D") right_top_border=$(echo -e "\u256E") left_bottom_border=$(echo -e "\u2570") right_bottom_border=$(echo -e "\u256F") box_break_line=$(echo -e "\u25A2") ;; msys ) top_border=${light_h} bottom_border=${light_h} left_border=${light_v} right_border=${light_v} left_top_border=$(echo -e "\u256D") right_top_border=$(echo -e "\u256E") left_bottom_border=$(echo -e "\u2570") right_bottom_border=$(echo -e "\u256F") box_break_line=$(echo -e "\u25A2") ;; esac # ---------------------------------------# } box-singlechar(){ # ---------------------------------------# top_border=$borderchar bottom_border=$borderchar left_border=$borderchar right_border=$borderchar left_top_border=$borderchar right_top_border=$borderchar left_bottom_border=$borderchar right_bottom_border=$borderchar box_break_line="-" # ---------------------------------------# } set-boxtype(){ case $boxtype in norm) box-norm ;; double) box-double ;; heavy) box-heavy ;; light) box-light ;; rounded) box-rounded ;; char) box-singlechar ;; esac } #set-boxtype repchar() { n=1 while [ $n -le $2 ] ; do echo -n "$1" n=$((n+1)) done } boxtop() { echo -n "$left_top_border" repchar "$top_border" $((BOXWIDTH-1)) echo -n "$right_top_border" echo } boxbottom() { echo -n "$left_bottom_border" repchar "$bottom_border" $((BOXWIDTH-1)) echo -n "$right_bottom_border" echo } boxline() { echo -e "$left_border $1\r${ESC}[${BOXWIDTH}C$right_border" } boxseparator(){ repchar "$box_break_line" $((BOXWIDTH-3)) echo } # # For printing center-justified text. To change the padding character, replace the ' ' <~~ whitespace in front of the '{' in the padding variable # center() { # padding="$(printf '%0.1s' {1..500})" # printf '%*.*s %s %*.*s\n' 0 "$(((terminal_width-2-${#1})/2))" "$padding" "$1" 0 "$(((termwidth-1-${#1})/2))" "$padding" # } # For printing center-justified text. To change the padding character, replace the ' ' <~~ whitespace in front of the '{' in the padding variable center() { local padding=""; padding="$(printf '%0.1s' \ {1..100})" #padding=" " printf '%*.*s %s %*.*s\n' 0 "$(((BOXWIDTH-2-${#1})/2))" "${padding}" "$1" 0 "$(((BOXWIDTH-1-${#1})/2))" "${padding}" } # For printing spanned text, e.g. single-pair lists ($name...$title) spanner() { # 1: left-side-text, 2: right-side-text local spanner=""; eval printf -v spanner \'"%0.1s"\' "-"{1..$[$((BOXWIDTH-4))- 2 - ${#1} - ${#2}]} printf "%s %s %s\n" "$1" "$spanner" "$2"; } boxborder(){ boxtop for line in "$@" ; do boxline "$line" done boxbottom } success(){ _line="$@" echo -e "\n" boxborder "${scriptname} ${grn}SUCCESS${dfl} ${_line}" exit 0 } warn(){ ec=$? _line="$@" echo -e "\n" boxtop boxline "${lrd}WARNING${lyl}[${ong}code=${red}$ec${lyl}]: ${_line}${dfl}" boxbottom } fail(){ ec=$? _line="$@" echo -e "\n" boxtop boxline "${lrd}FAILED${lyl}[${ong}code=${red}$ec${lyl}]: ${_line}${dfl}" boxbottom exit $ec } pushd(){ command pushd "$@" > /dev/null } popd(){ command popd "$@" > /dev/null } popdfail(){ ec=$? popd $(exit $ec) #restore the exit code fail "$@" } logger(){ #$@ 2>&1 | tee >(ts "[$scriptname][%d-%m-%y %H_%M_%S]" > $logfile) # This version of prepend requires the 'ts' utility from 'moreutils' package $@ 2>&1 | tee >( while IFS= read -r line; do _line=$(echo $line | sed "s,\x1B\[[0-9;]*[mK],,g" | tr -dc '[:print:]') printf '[%s] %s\n' "${scriptname}][${prettyDate}" "$_line" done >> $logfile ) } ctrl_c(){ echo -e "\n" fail "User interrupted with Ctrl-C" } # ensure ctrl-c to cancel script ends the entire process and not just the current function # trap ctrl_c INT # Commented out by default to prevent abnormal background exits # Function for spinner status sp="/-\|" sc=0 spin() { printf "\b${sp:sc++:1}" ((sc==${#sp})) && sc=0 } endspin() { printf "\r%s\n" "$@" } # Example usage for above: # until work_done; do # spin # some_work ... # done # endspin # https://github.com/fearside/ProgressBar/blob/master/progressbar.sh progress-bar() { # Process data let _progress=(${1}*100/${2}*100)/100 let _done=(${_progress}*4)/10 let _left=40-$_done # Build progressbar string lengths _done=$(printf "%${_done}s") _left=$(printf "%${_left}s") # 1.2 Build progressbar strings and print the ProgressBar line # 1.2.1 Output example: # 1.2.1.1 Progress : [########################################] 100% printf "\rProgress : [${_done// /#}${_left// /-}] ${_progress}%%" } # Renders a text based list of options that can be selected by the # user using up, down and enter keys and returns the chosen option. # # Arguments : list of options, maximum of 256 # "opt1" "opt2" ... # Return value: selected index (0 for opt1, 1 for opt2 ...) select_option(){ # little helpers for terminal print control and key input cursor_blink_on() { printf "$ESC[?25h"; } cursor_blink_off() { printf "$ESC[?25l"; } cursor_to() { printf "$ESC[$1;${2:-1}H"; } print_option() { printf " $1 "; } print_selected() { printf " $ESC[7m $1 $ESC[27m"; } get_cursor_row() { IFS=';' read -sdR -p $'\E[6n' ROW COL; echo ${ROW#*[}; } key_input() { read -s -n3 key 2>/dev/null >&2 if [[ $key = $ESC[A ]]; then echo up; fi if [[ $key = $ESC[B ]]; then echo down; fi if [[ $key = "" ]]; then echo enter; fi; } # initially print empty new lines (scroll down if at bottom of screen) for opt; do printf "\n"; done # determine current screen position for overwriting the options local lastrow=`get_cursor_row` local startrow=$(($lastrow - $#)) # ensure cursor and input echoing back on upon a ctrl+c during read -s trap "cursor_blink_on; stty echo; printf '\n'; exit" 2 cursor_blink_off local selected=0 while true; do # print options by overwriting the last lines local idx=0 for opt; do cursor_to $(($startrow + $idx)) if [ $idx -eq $selected ]; then print_selected "$opt" else print_option "$opt" fi ((idx++)) done # user key control case `key_input` in enter) break;; up) ((selected--)); if [ $selected -lt 0 ]; then selected=$(($# - 1)); fi;; down) ((selected++)); if [ $selected -ge $# ]; then selected=0; fi;; esac done # cursor position back to normal cursor_to $lastrow printf "\n" cursor_blink_on return $selected } # Example for above select_option #echo "Select one option using up/down keys and enter to confirm:" #echo #options=("one" "two" "three") #select_option "${options[@]}" #choice=$? #echo "Choosen index = $choice" #echo " value = ${options[$choice]}" select_opt(){ select_option "$@" 1>&2 local result=$? echo $result return $result } # Examples for above select_opt #case `select_opt "Yes" "No" "Cancel"` in # 0) echo "selected Yes";; # 1) echo "selected No";; # 2) echo "selected Cancel";; #esac #options=("Yes" "No" "${array[@]}") # join arrays to add some variable array #case `select_opt "${options[@]}"` in # 0) echo "selected Yes";; # 1) echo "selected No";; # *) echo "selected ${options[$?]}";; #esac multiselect(){ # little helpers for terminal print control and key input cursor_blink_on() { printf "$ESC[?25h"; } cursor_blink_off() { printf "$ESC[?25l"; } cursor_to() { printf "$ESC[$1;${2:-1}H"; } print_inactive() { printf "$2 $1 "; } print_active() { printf "$2 $ESC[7m $1 $ESC[27m"; } get_cursor_row() { IFS=';' read -sdR -p $'\E[6n' ROW COL; echo ${ROW#*[}; } local return_value=$1 local -n options=$2 local -n defaults=$3 local selected=() for ((i=0; i<${#options[@]}; i++)); do if [[ ${defaults[i]} = "true" ]]; then selected+=("true") else selected+=("false") fi printf "\n" done # determine current screen position for overwriting the options local lastrow=`get_cursor_row` local startrow=$(($lastrow - ${#options[@]})) # ensure cursor and input echoing back on upon a ctrl+c during read -s trap "cursor_blink_on; stty echo; printf '\n'; exit" 2 cursor_blink_off key_input() { local key IFS= read -rsn1 key 2>/dev/null >&2 if [[ $key = "" ]]; then echo enter; fi; if [[ $key = $'\x20' ]]; then echo space; fi; if [[ $key = "k" ]]; then echo up; fi; if [[ $key = "j" ]]; then echo down; fi; if [[ $key = $'\x1b' ]]; then read -rsn2 key if [[ $key = [A || $key = k ]]; then echo up; fi; if [[ $key = [B || $key = j ]]; then echo down; fi; fi } toggle_option() { local option=$1 if [[ ${selected[option]} == true ]]; then selected[option]=false else selected[option]=true fi } print_options() { # print options by overwriting the last lines local idx=0 for option in "${options[@]}"; do #local prefix="[ ]" local prefix="${gry}${deselected_opt}${dfl}" if [[ ${selected[idx]} == true ]]; then #prefix="[\e[38;5;46m✔\e[0m]" prefix="${selected_opt}" fi cursor_to $(($startrow + $idx)) if [ $idx -eq $1 ]; then print_active "$option" "$prefix" else print_inactive "$option" "$prefix" fi ((idx++)) done } local active=0 while true; do print_options $active # user key control case `key_input` in space) toggle_option $active;; enter) print_options -1; break;; up) ((active--)); if [ $active -lt 0 ]; then active=$((${#options[@]} - 1)); fi;; down) ((active++)); if [ $active -ge ${#options[@]} ]; then active=0; fi;; esac done # cursor position back to normal cursor_to $lastrow printf "\n" cursor_blink_on eval $return_value='("${selected[@]}")' } # Example for above multiselect functions #my_options=( "Option 1" "Option 2" "Option 3" ) #preselection=( "true" "true" "false" ) #multiselect result my_options preselection #idx=0 #for option in "${my_options[@]}"; do # echo -e "$option\t=> ${result[idx]}" # ((idx++)) #done ### IP validation function valid-ip() { local ip=$1 local stat=1 if [[ $ip =~ ^[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}$ ]]; then OIFS=$IFS IFS='.' ip=($ip) IFS=$OIFS [[ ${ip[0]} -le 255 && ${ip[1]} -le 255 \ && ${ip[2]} -le 255 && ${ip[3]} -le 255 ]] stat=$? fi return $stat } # Version comparison function # usage: # vercomp [first version] [second version] # output: # 0 = # 1 > # 2 < vercomp() { if [[ $1 == $2 ]] then return 0 fi local IFS=. local i ver1=($1) ver2=($2) # fill empty fields in ver1 with zeros for ((i=${#ver1[@]}; i<${#ver2[@]}; i++)) do ver1[i]=0 done for ((i=0; i<${#ver1[@]}; i++)) do if [[ -z ${ver2[i]} ]] then # fill empty fields in ver2 with zeros ver2[i]=0 fi if ((10#${ver1[i]} > 10#${ver2[i]})) then return 1 fi if ((10#${ver1[i]} < 10#${ver2[i]})) then return 2 fi done return 0 } compare-versions() { vercomp $1 $2 case $? in 0) op='=';; 1) op='>';; 2) op='<';; esac if [[ $op != $3 ]] then echo "Fail: Expected '$3', Actual '$op', Arg1 '$1', Arg2 '$2'" else echo "Pass: '$1 $op $2'" fi } set-boxtype