Skip to content

Instantly share code, notes, and snippets.

@CoeJoder
Last active August 13, 2025 12:20
Show Gist options
  • Save CoeJoder/6e47db3d603810ede3d79500ef58c400 to your computer and use it in GitHub Desktop.
Save CoeJoder/6e47db3d603810ede3d79500ef58c400 to your computer and use it in GitHub Desktop.
`choose_from_menu()` bash function
# in-place shell selection list
# original by Guss: https://askubuntu.com/a/1386907
# improvements: syntax cleanup, shellcheck-linted, cyclic menu selection, compatible with `set -e`
#
# example usage:
# apples=("Red Delicious" "Granny" "Cosmic Crisp")
# choose_from_menu "Select an apple:" chosen "${apples[@]}"
# echo "You chose: $chosen"
function choose_from_menu() {
local -r prompt="$1" outvar="$2" options=("${@:3}")
local -i cur=0 count=${#options[@]} index=0
local esc
esc=$(echo -en "\e") # cache ESC as test doesn't allow esc codes
printf "%s\n" "$prompt"
while true; do
# list all options (option list is zero-based)
index=0
for o in "${options[@]}"; do
if ((index == cur)); then
echo -e " >\e[7m$o\e[0m" # mark & highlight the current option
else
echo " $o"
fi
index=$((index+1))
done
IFS= read -rs -n3 key # wait for user to key in arrows or ENTER
if [[ $key == "${esc}[A" ]]; then # up arrow
cur=$((cur-1))
((cur < 0)) && cur=$((count - 1))
elif [[ $key == "${esc}[B" ]]; then # down arrow
cur=$((cur+1))
((cur >= count)) && cur=0
elif [[ $key == "" ]]; then # nothing, i.e the read delimiter - ENTER
break
fi
echo -en "\e[${count}A" # go up to the beginning to re-render
done
# export the selection to the requested output variable
printf -v "$outvar" "%s" "${options[$cur]}"
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment