Last active
July 27, 2020 20:37
-
-
Save dekarrin/3e213e7bf915bbbd75c0 to your computer and use it in GitHub Desktop.
Various prompting tasks in bash
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
# This file is not intended to be executed. | |
# Source this script from other scripts. | |
# replacement for realpath on posix systems that lack it | |
findrealpath() { | |
[ "$#" = 1 ] || { echo "usage: findpath path" >&2 ; return 1 ; } | |
[ ! "$1" = "/" ] || { echo "/" ; return 0 ; } | |
canonpath="$(cd "$(dirname "$1")" && pwd -P)" || return 1 | |
separator="/" | |
[ ! "$canonpath" = "/" ] || separator= | |
base="$(basename "$1")" | |
if [ "$base" = "." ] | |
then | |
base= | |
separator= | |
fi | |
path="$canonpath$separator$base" | |
if [ -L "$path" ] | |
then | |
# if it IS a real path to a symlink, resolve it via recursive call | |
path="$(readlink "$path")" || return 1 | |
if [ -d "$path" ] | |
then | |
$(cd "$path") || return 1 | |
findrealpath "$path" || return 1 | |
else | |
echo "$path" | |
fi | |
else | |
# if not a path to a real symlink, dont do anything further | |
echo "$path" | |
fi | |
} | |
_PROMPT_FUNCTS_TRIM= | |
_prompt_preproc () | |
{ | |
local i | |
i="$1" | |
if [ -n "$_PROMPT_FUNCTS_TRIM" ] | |
then | |
i="$(echo "$i" | sed 's/^ *\| *$//g')" | |
fi | |
echo "$i" | |
} | |
# Makes it so all prompt functions trim input before reading it. | |
# $1 - If 0 (or none), turns off prompt trimming. If 1 (or anything else), turns | |
# it on. | |
set_prompt_trim () | |
{ | |
if [ -z "$1" -o "$1" = 0 ] | |
then | |
_PROMPT_FUNCTS_TRIM= | |
else | |
_PROMPT_FUNCTS_TRIM=1 | |
fi | |
} | |
# Prompts, and if no input, returns a default. | |
# $1 - Prompt to show user | |
# $2 - What to return if user enters no input | |
prompt_default () | |
{ | |
local inp | |
read -p "$1 (default '$2'): " inp | |
inp="$(_prompt_preproc "$inp")" | |
if [ -z "$inp" ] | |
then | |
inp="$2" | |
fi | |
echo "$inp" | |
} | |
# Prompts until user enters integer. | |
# $1 - Prompt to show user | |
prompt_num () | |
{ | |
local inp | |
while true | |
do | |
read -p "$1 (integer): " inp | |
inp="$(_prompt_preproc "$inp")" | |
case "$inp" in | |
''|*[!0-9]*) ;; | |
*) break ;; | |
esac | |
done | |
echo "$inp" | |
} | |
# Prompts user for integer. Returns default value if invalid value is entered. | |
# $1 - Prompt to show user | |
# $2 - What to return if user enters no input | |
prompt_num_default () | |
{ | |
local inp | |
read -p "$1 (default '$2'): " inp | |
inp="$(_prompt_preproc "$inp")" | |
case "$inp" in | |
''|*[!0-9]*) inp="$2";; | |
*) ;; | |
esac | |
echo "$inp" | |
} | |
# Prompts until user enters integer in given range. | |
# $1 - Prompt to show user | |
# $2 - Start of range (inclusive) | |
# $3 - End of range (inclusive) | |
prompt_range () | |
{ | |
local range_start | |
local range_end | |
local inp | |
range_start="$2" | |
range_end="$3" | |
if [ $range_start -gt $range_end ] | |
then | |
local t | |
t=$range_start | |
range_start=$range_end | |
range_end=$t | |
fi | |
while true | |
do | |
inp=$(prompt_num "$1 (${range_start}-${range_end})") | |
if [ $inp -ge $range_start -a $inp -le $range_end ] | |
then | |
break | |
fi | |
done | |
echo "$inp" | |
} | |
# Prompts for integer in range. Returns default if user enters an invalid value. | |
# $1 - Prompt to show user | |
# $2 - Start of range (inclusive) | |
# $3 - End of range (inclusive) | |
# $4 - Default value | |
prompt_range_default () | |
{ | |
local range_start | |
local range_end | |
local inp | |
range_start="$2" | |
range_end="$3" | |
if [ $range_start -gt $range_end ] | |
then | |
local t | |
t=$range_start | |
range_start=$range_end | |
range_end=$t | |
fi | |
inp=$(prompt_num_default "$1 (${range_start}-${range_end})" "$4") | |
if [ $inp -lt $range_start -o $inp -gt $range_end ] | |
then | |
inp="$4" | |
fi | |
echo "$inp" | |
} | |
# Prompts for confirmation. Returns 1 if yes and nothing if no. | |
# $1 - Prompt to show user | |
prompt_confirm () | |
{ | |
local inp | |
while true | |
do | |
read -p "$1 (y/n): " inp | |
inp="$(_prompt_preproc "$inp")" | |
case $inp in | |
[Yy]*) | |
echo 1 | |
break | |
;; | |
[Nn]*) | |
break | |
;; | |
*) | |
;; | |
esac | |
done | |
} | |
# Prompts for an item from a menu. The menu is paginated, with 10 menu items | |
# per page. The user is prompted until an item is selected. | |
# $1 - Prompt to show user. This will be at the top of the selection menu. | |
# $2-... - The options that the user may select from. This will also be return | |
# value of this function | |
prompt_select() | |
{ | |
local items_per_page=10 | |
local prompt | |
local -a options | |
local -a page_options | |
local inp | |
local page=0 | |
# load args | |
prompt="$1" | |
shift | |
while (( "$#" )) | |
do | |
options=("${options[@]}" "$1") | |
shift | |
done | |
local print_linebreak=0 | |
while true | |
do | |
# get the options currently being displayed: | |
local -a prev_opt=() | |
local -a next_opt=() | |
local item_count=$items_per_page | |
local prior_items=$(( page * (items_per_page - 2) )) | |
if [[ "$prior_items" -gt 0 ]]; then (( prior_items++ )); fi | |
local remaining_items=$(( ${#options[@]} - prior_items )) | |
if [[ "$remaining_items" -gt "$items_per_page" ]] | |
then | |
next_opt=("(next page)") | |
(( item_count-- )) | |
fi | |
if [[ "$page" -gt 0 ]] | |
then | |
prev_opt=("(previous page)") | |
(( item_count-- )) | |
fi | |
page_options=("${prev_opt[@]}" "${options[@]:$prior_items:$item_count}" "${next_opt[@]}") | |
# print the prompt | |
local opt_num=0 | |
local opt | |
local menu_prompt="$prompt" | |
if [[ $print_linebreak = 1 ]] | |
then | |
menu_prompt=" | |
$menu_prompt" | |
fi | |
for opt in "${page_options[@]}" | |
do | |
menu_prompt="$menu_prompt | |
$opt_num) $opt" | |
(( opt_num++ )) | |
done | |
menu_prompt="$menu_prompt | |
" | |
# now get the input | |
local max_opt=$(( ${#page_options[@]} - 1 )) | |
inp=$(prompt_range "${menu_prompt}select" 0 $max_opt) | |
print_linebreak=1 | |
if [[ ${#prev_opt[@]} != 0 && $inp = 0 ]] | |
then | |
(( page-- )) | |
elif [[ ${#next_opt[@]} != 0 && $inp = $max_opt ]] | |
then | |
(( page++ )) | |
else | |
echo "${page_options[$inp]}" | |
break | |
fi | |
done | |
} | |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment