Как я могу создать меню выбора в сценарии оболочки?
Я создаю простой скрипт bash и хочу создать в нем меню выбора, например:
$./script
echo "Choose your option:"
1) Option 1
2) Option 2
3) Option 3
4) Quit
И по выбору пользователя я хочу, чтобы выполнялись разные действия. Я noob, пишущий для bash, я искал ответы в Интернете, но ничего конкретного не получил.
12 ответов
#!/bin/bash
# Bash Menu Script Example
PS3='Please enter your choice: '
options=("Option 1" "Option 2" "Option 3" "Quit")
select opt in "${options[@]}"
do
case $opt in
"Option 1")
echo "you chose choice 1"
;;
"Option 2")
echo "you chose choice 2"
;;
"Option 3")
echo "you chose choice $REPLY which is $opt"
;;
"Quit")
break
;;
*) echo "invalid option $REPLY";;
esac
done
добавлять break заявления, где вам нужно select цикл для выхода. Если break не выполняется, select оператор зацикливается и меню отображается заново.
В третий вариант я включил переменные, которые устанавливаются select заявление, чтобы продемонстрировать, что у вас есть доступ к этим ценностям. Если вы выберете его, он выведет:
you chose choice 3 which is Option 3
Ты это видишь $REPLY содержит строку, введенную вами в командной строке. Используется как индекс в массиве ${options[@]} как если бы массив был основан на 1. Переменная $opt содержит строку из этого индекса в массиве.
Обратите внимание, что выбор может быть простым списком прямо в select утверждение как это:
select opt in foo bar baz 'multi word choice'
но вы не можете поместить такой список в скалярную переменную из-за пробелов в одном из вариантов.
Вы также можете использовать глобирование файлов, если вы выбираете среди файлов:
select file in *.tar.gz
С помощью dialog команда будет выглядеть так:
dialog --clear --backtitle "Backtitle here" --title "Заголовок здесь" --menu "Выберите один из следующих параметров:" 15 40 4 \ 1 "Вариант 1" \ 2 "Вариант 2" \ 3 "Вариант 3"
Поместив это в скрипт:
#!/bin/bash
HEIGHT=15
WIDTH=40
CHOICE_HEIGHT=4
BACKTITLE="Backtitle here"
TITLE="Title here"
MENU="Choose one of the following options:"
OPTIONS=(1 "Option 1"
2 "Option 2"
3 "Option 3")
CHOICE=$(dialog --clear \
--backtitle "$BACKTITLE" \
--title "$TITLE" \
--menu "$MENU" \
$HEIGHT $WIDTH $CHOICE_HEIGHT \
"${OPTIONS[@]}" \
2>&1 >/dev/tty)
clear
case $CHOICE in
1)
echo "You chose Option 1"
;;
2)
echo "You chose Option 2"
;;
3)
echo "You chose Option 3"
;;
esac
Сам по себе не новый ответ, но поскольку пока что нет принятого ответа, вот несколько советов и рекомендаций по кодированию, как для избранных, так и для zenity:
title="Select example"
prompt="Pick an option:"
options=("A" "B" "C")
echo "$title"
PS3="$prompt "
select opt in "${options[@]}" "Quit"; do
case "$REPLY" in
1 ) echo "You picked $opt which is option $REPLY";;
2 ) echo "You picked $opt which is option $REPLY";;
3 ) echo "You picked $opt which is option $REPLY";;
$(( ${#options[@]}+1 )) ) echo "Goodbye!"; break;;
*) echo "Invalid option. Try another one.";continue;;
esac
done
while opt=$(zenity --title="$title" --text="$prompt" --list \
--column="Options" "${options[@]}"); do
case "$opt" in
"${options[0]}" ) zenity --info --text="You picked $opt, option 1";;
"${options[1]}" ) zenity --info --text="You picked $opt, option 2";;
"${options[2]}" ) zenity --info --text="You picked $opt, option 3";;
*) zenity --error --text="Invalid option. Try another one.";;
esac
done
Стоит отметить:
Оба будут зациклены, пока пользователь явно не выберет Выход (или Отмена для zenity). Это хороший подход для интерактивных меню сценариев: после выбора и выполнения действия снова открывается меню для другого выбора. Если выбор должен быть одноразовым, просто используйте
breakпослеesac(подход zenity может быть дополнительно уменьшен)Обе
caseоснованы на индексе, а не на стоимости. Я думаю, что это легче кодировать и поддерживатьМассив также используется для
zenityподход.Опция "Выйти" не входит в число первоначальных, оригинальных опций. Он добавляется при необходимости, поэтому ваш массив остается чистым. В конце концов, "Выход" не нужен для zenity, пользователь может просто нажать "Отмена" (или закрыть окно), чтобы выйти. Обратите внимание, как оба используют один и тот же нетронутый массив параметров.
PS3а такжеREPLYVars не может быть переименован.selectжестко запрограммирован, чтобы использовать их. Все остальные переменные в скрипте (opt, options, prompt, title) могут иметь любые имена, которые вы хотите, при условии, что вы делаете корректировки
Вы можете использовать этот простой скрипт для создания опций
#!/ Bin/ Баш echo "выберите операцию ************" эхо " 1) операция 1" эхо " 2) операция 2" эхо " 3) операция 3" эхо " 4) операция 4"
читай дело $n в 1) эхо "Вы выбрали вариант 1";; 2) эхо "Вы выбрали вариант 2";; 3) эхо "Вы выбрали вариант 3";; 4) эхо "Вы выбрали вариант 4";; *) echo "неверная опция";; ESAC
У меня есть еще один вариант, который представляет собой смесь этих ответов, но что приятно, так это то, что вам нужно всего лишь нажать одну клавишу, а затем сценарий продолжается благодаря -n вариант чтения. В этом примере мы предлагаем завершить работу, перезагрузить компьютер или просто выйти из сценария, используя ANS поскольку наша переменная и пользователю нужно только нажать E, R или S. Я также установил значение по умолчанию для выхода, поэтому, если нажата клавиша enter, скрипт завершится.
read -n 1 -p "Would you like to exit, reboot, or shutdown? (E/r/s) " ans;
case $ans in
r|R)
sudo reboot;;
s|S)
sudo poweroff;;
*)
exit;;
esac
#!/bin/sh
show_menu(){
normal=`echo "\033[m"`
menu=`echo "\033[36m"` #Blue
number=`echo "\033[33m"` #yellow
bgred=`echo "\033[41m"`
fgred=`echo "\033[31m" printf "\n${menu}*********************************************${normal}\n"
printf "${menu}**${number} 1)${menu} Смонтировать Dropbox ${normal}\n"
printf "${menu}**${number} 2)${menu} Монтирование USB 500 Gig Drive ${normal}\n"
printf "${menu}**${number} 3)${menu} Перезапустите Apache ${normal}\n"
printf "${menu}**${number} 4)${menu} ssh Frost TomCat Server ${normal}\n"
printf "${menu}**${number} 5)${menu} Некоторые другие команды $ {normal} \ n "printf" $ {menu} ************************ ********************* $ {normal} \ n "printf" Пожалуйста, введите опцию меню и введите или ${fgred}x для выхода. ${normal}"
read opt
}
option_picked(){
msgcolor=`echo "\033[01;31m"` # bold red
normal=`echo "\033[00;00m"` # normal white
message=${@:-"${normal} Ошибка: сообщение не передано "}
printf "${msgcolor}${message}${normal}\n"
}
clear
show_menu, в то время как [ $opt!= '' ] делает if [ $opt = '' ]; затем выйдите; в противном случае $opt in
1) clear;
option_picked "Выбранный вариант 1";
printf "sudo mount /dev/sdh1 /mnt/DropBox/; # 3 терабайта";
show_menu;;;
2) очистить;
option_picked "Option 2 Picked";
printf "sudo mount /dev/sdi1 /mnt/usbDrive; # диск на 500 гигов";
show_menu;;;
3) очистить; option_picked "Выбранный вариант 3";
printf "sudo service apache2 restart";
show_menu;;;
4) очистить; option_picked "Выбранный вариант 4";
printf "ssh lmesser@ -p 2010";
show_menu;;; х) выход;;; \ П) выход;;;
*)Чисто; option_picked "Выбрать опцию из меню";
show_menu;;;
esac
fi сделано
Если вам нужно только очень простое меню, которое показывает «на месте», и вы можете продолжать печатать после этого — без какой-либо причудливой внешней диалоговой программы, тогда вы можете использовать escape-последовательности ANSI и простой цикл для отображения списка и позволить курсору быть переместился поверх него.
В ответе здесь от пользователя 360154 уже есть все, что вам нужно, но он также очень причудливый, делает гораздо больше, чем нужно, и хотя код также отформатирован, чтобы выглядеть причудливо, его нелегко читать и понимать.
Здесь тот же подход, что и у пользователя 360154, но намного проще:
function choose_from_menu() {
local prompt="$1" outvar="$2"
shift
shift
local options=("$@") cur=0 count=${#options[@]} index=0
local esc=$(echo -en "\e") # cache ESC as test doesn't allow esc codes
printf "$prompt\n"
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
read -s -n3 key # wait for user to key in arrows or ENTER
if [[ $key == $esc[A ]] # up arrow
then cur=$(( $cur - 1 ))
[ "$cur" -lt 0 ] && cur=0
elif [[ $key == $esc[B ]] # down arrow
then cur=$(( $cur + 1 ))
[ "$cur" -ge $count ] && cur=$(( $count - 1 ))
elif [[ $key == "" ]] # nothing, i.e the read delimiter - ENTER
then 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 "${options[$cur]}"
}
Вот пример использования:
selections=(
"Selection A"
"Selection B"
"Selection C"
)
choose_from_menu "Please make a choice:" selected_choice "${selections[@]}"
echo "Selected choice: $selected_choice"
Bash необычное меню
Попробуйте сначала, а затем посетите мою страницу для подробного описания... Нет необходимости во внешних библиотеках или программах, таких как диалог или zenity ...
#/bin/bash
# by oToGamez
# www.pro-toolz.net
E='echo -e';e='echo -en';trap "R;exit" 2
ESC=$( $e "\e")
TPUT(){ $e "\e[${1};${2}H";}
CLEAR(){ $e "\ec";}
CIVIS(){ $e "\e[?25l";}
DRAW(){ $e "\e%@\e(0";}
WRITE(){ $e "\e(B";}
MARK(){ $e "\e[7m";}
UNMARK(){ $e "\e[27m";}
R(){ CLEAR ;stty sane;$e "\ec\e[37;44m\e[J";};
HEAD(){ DRAW
for each in $(seq 1 13);do
$E " x x"
done
WRITE;MARK;TPUT 1 5
$E "BASH SELECTION MENU ";UNMARK;}
i=0; CLEAR; CIVIS;NULL=/dev/null
FOOT(){ MARK;TPUT 13 5
printf "ENTER - SELECT,NEXT ";UNMARK;}
ARROW(){ read -s -n3 key 2>/dev/null >&2
if [[ $key = $ESC[A ]];then echo up;fi
if [[ $key = $ESC[B ]];then echo dn;fi;}
M0(){ TPUT 4 20; $e "Login info";}
M1(){ TPUT 5 20; $e "Network";}
M2(){ TPUT 6 20; $e "Disk";}
M3(){ TPUT 7 20; $e "Routing";}
M4(){ TPUT 8 20; $e "Time";}
M5(){ TPUT 9 20; $e "ABOUT ";}
M6(){ TPUT 10 20; $e "EXIT ";}
LM=6
MENU(){ for each in $(seq 0 $LM);do M${each};done;}
POS(){ if [[ $cur == up ]];then ((i--));fi
if [[ $cur == dn ]];then ((i++));fi
if [[ $i -lt 0 ]];then i=$LM;fi
if [[ $i -gt $LM ]];then i=0;fi;}
REFRESH(){ after=$((i+1)); before=$((i-1))
if [[ $before -lt 0 ]];then before=$LM;fi
if [[ $after -gt $LM ]];then after=0;fi
if [[ $j -lt $i ]];then UNMARK;M$before;else UNMARK;M$after;fi
if [[ $after -eq 0 ]] || [ $before -eq $LM ];then
UNMARK; M$before; M$after;fi;j=$i;UNMARK;M$before;M$after;}
INIT(){ R;HEAD;FOOT;MENU;}
SC(){ REFRESH;MARK;$S;$b;cur=`ARROW`;}
ES(){ MARK;$e "ENTER = main menu ";$b;read;INIT;};INIT
while [[ "$O" != " " ]]; do case $i in
0) S=M0;SC;if [[ $cur == "" ]];then R;$e "\n$(w )\n";ES;fi;;
1) S=M1;SC;if [[ $cur == "" ]];then R;$e "\n$(ifconfig )\n";ES;fi;;
2) S=M2;SC;if [[ $cur == "" ]];then R;$e "\n$(df -h )\n";ES;fi;;
3) S=M3;SC;if [[ $cur == "" ]];then R;$e "\n$(route -n )\n";ES;fi;;
4) S=M4;SC;if [[ $cur == "" ]];then R;$e "\n$(date )\n";ES;fi;;
5) S=M5;SC;if [[ $cur == "" ]];then R;$e "\n$($e by oTo)\n";ES;fi;;
6) S=M6;SC;if [[ $cur == "" ]];then R;exit 0;fi;;
esac;POS;done
Я использовал Zenity, который, кажется, всегда есть в Ubuntu, работает очень хорошо и имеет много возможностей. Это эскиз возможного меню:
#! /bin/bash
selection=$(zenity --list "Option 1" "Option 2" "Option 3" --column="" --text="Text above column(s)" --title="My menu")
case "$selection" in
"Option 1")zenity --info --text="Do something here for No1";;
"Option 2")zenity --info --text="Do something here for No2";;
"Option 3")zenity --info --text="Do something here for No3";;
esac
Так как это нацелено на Ubuntu, вы должны использовать любой бэкэнд debconf, настроенный для использования. Вы можете узнать бэкэнд debconf с помощью:
sudo -s "echo get debconf/frontend | debconf-communicate"
Если он говорит "диалог", то он, вероятно, использует whiptail или же dialog, На Люсиде это whiptail,
Если это не поможет, используйте bash "select", как объяснил Деннис Уильямсон.
Там уже тот же вопрос в ответе сервера. Решение там использует хлыст.
Предполагая, что вы хотите использовать простое меню сценария оболочки (без необычного пользовательского интерфейса), посмотрите пример меню на http://www.tldp.org/LDP/abs/html/testbranch.html.

