PRbL/functions

994 lines
26 KiB
Bash
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

#!/bin/bash
# pyr0ball script functions library
# Initial Vars
functionsrev=1.1.7
scriptname="${0##*/}"
rundir="${0%/*}"
rundir_absolute=$(cd $rundir && pwd)
runuser="$(whoami)"
pretty_date="$(date +%Y-%m-%d_%H-%M-%S)"
short_date="$(date +%Y-%m-%d)"
# return any cursor mods to normal on exit
cleanup(){
tput cnorm
}
trap cleanup EXIT
# 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
}
subboxborder(){
BOXWIDTH_ORG=$BOXWIDTH
BOXWIDTH=$(($BOXWIDTH*75/100))
boxline $(boxtop)
for line in "$@" ; do
boxline $(boxline "$line")
done
boxline $(boxbottom)
BOXWIDTH=$BOXWIDTH_ORG
}
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
# usage: spin "command [args]"
set_spinner() {
case $1 in
spinner1)
FRAME="⠋⠙⠹⠸⠼⠴⠦⠧⠇⠏"
FRAME_INTERVAL=0.05
;;
spinner2)
FRAME="-\|/"
FRAME_INTERVAL=0.1
;;
spinner3)
FRAME="◐◓◑◒"
FRAME_INTERVAL=0.2
;;
spinner4)
FRAME="⇐⇖⇑⇗⇒⇘⇓⇙"
FRAME_INTERVAL=0.1
;;
spinner5)
FRAME="◇◈◆◈"
FRAME_INTERVAL=0.2
;;
spinner6)
FRAME="⚬⚭⚮⚯⚮⚭"
FRAME_INTERVAL=0.15
;;
spinner7)
FRAME="░▒▓█▓▒"
FRAME_INTERVAL=0.2
;;
spinner8)
FRAME="☉◎◉◎☉"
FRAME_INTERVAL=0.1
;;
spinner9)
FRAME="♡♥❤♥♡"
FRAME_INTERVAL=0.15
;;
spinner10)
FRAME="▁▂▃▄▅▆▇█▇▆▅▄▃▂▁"
FRAME_INTERVAL=0.1
;;
spinner11)
FRAME="←↖↑↗→↘↓↙"
FRAME_INTERVAL=0.1
;;
spinner12)
FRAME="▖▘▝▗"
FRAME_INTERVAL=0.2
;;
spinner13)
FRAME="▙▛▜▟"
FRAME_INTERVAL=0.2
;;
spinner14)
FRAME="▚▞"
FRAME_INTERVAL=0.5
;;
spinner15)
FRAME="☰☱☳☶☵☳☶☴☰☰"
FRAME_INTERVAL=0.1
;;
spinner16)
FRAME="▤▧▥▨"
FRAME_INTERVAL=0.2
;;
spinner17)
FRAME="▉▊▋▌▍▎▏▎▍▌▋▊▉"
FRAME_INTERVAL=0.1
;;
spinner18)
FRAME="⣾⣽⣻⢿⡿⣟⣯⣷"
FRAME_INTERVAL=0.1
;;
spinner19)
FRAME="┤┘┴└├┌┬┐"
FRAME_INTERVAL=0.1
;;
*)
warn "No spinner is defined for $1"
esac
}
spin() {
CMD=$@
tput civis
sc=0
$CMD &
_PID=$!
while [ -d /proc/$_PID ] ; do
for i in "${FRAME[@]}" ; do
printf "\b${FRAME:sc++:1}"
((sc==${#FRAME})) && sc=0
#echo -ne "\b${FRAME[$i]}"
sleep $FRAME_INTERVAL
done
done
printf "\r\n"
tput cnorm
}
spinstart() {
sstop=false
tput civis
sc=0
while [[ $sstop == false ]] ; do
for i in "${FRAME[@]}" ; do
printf "\b${FRAME:sc++:1}"
((sc==${#FRAME})) && sc=0
#echo -ne "\b${FRAME[$i]}"
sleep $FRAME_INTERVAL
done
done
}
spinstop() {
export sstop=true
printf "\r\n"
tput cnorm
}
# 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
# returns 0 (true) for valid, 1 (false) for invalid
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
# version 1 is greater than version 2
return 1
fi
if ((10#${ver1[i]} < 10#${ver2[i]}))
then
# version 1 is less than version 2
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