Aquí hay una bashsolución de secuencia de comandos pura en forma de select_optionfunción, que se basa únicamente en secuencias de escape ANSI y en la función integrada read.
Funciona en Bash 4.2.45 en OSX. Las partes cobardes que podrían no funcionar igual de bien en todos los ambientes de todo lo que sé son los get_cursor_row(), key_input()(para detectar arriba / abajo) y las cursor_to()funciones.
#!/usr/bin/env bash
# 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 ...)
function select_option {
# little helpers for terminal print control and key input
ESC=$( printf "\033")
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
}
Aquí hay un ejemplo de uso:
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]}"
La salida se ve a continuación, con la opción seleccionada actualmente resaltada usando coloración ansi inversa (difícil de transmitir aquí en la reducción). Esto se puede adaptar en la print_selected()función si se desea.
Select one option using up/down keys and enter to confirm:
[one]
two
three
Actualización: Aquí hay una pequeña extensión que select_optajusta la select_optionfunción anterior para que sea fácil de usar en una casedeclaración:
function select_opt {
select_option "$@" 1>&2
local result=$?
echo $result
return $result
}
Ejemplo de uso con 3 opciones literales:
case `select_opt "Yes" "No" "Cancel"` in
0) echo "selected Yes";;
1) echo "selected No";;
2) echo "selected Cancel";;
esac
También puede mezclar si hay algunas entradas conocidas (Sí y No en este caso), y aprovechar el código de salida $?para el caso comodín:
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
tput, pero creo que lo primero no es posible), pero puede crear menús simples en bash conselect: tldp.org/LDP/Bash-Beginners-Guide/html/sect_09_06.html