Я создаю простой сценарий bash и хочу создать в нем меню выбора, например:
$./script
echo "Choose your option:"
1) Option 1
2) Option 2
3) Option 3
4) Quit
И, по выбору пользователя, я хочу, чтобы выполнялись разные действия. Я noob, пишущий в bash, я искал ответы в Интернете, но ничего конкретного не получил.
#!/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
Вы можете использовать этот простой сценарий для создания опций
#!/bin/bash echo "select the operation ************" echo " 1)operation 1" echo " 2)operation 2" echo " 3)operation 3" echo " 4)operation 4"
read n case $n in 1) echo "You chose Option 1";; 2) echo "You chose Option 2";; 3) echo "You chose Option 3";; 4) echo "You chose Option 4";; *) echo "invalid option";; 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} Mount dropbox ${normal}\n" printf "${menu}**${number} 2)${menu} Mount USB 500 Gig Drive ${normal}\n" printf "${menu}**${number} 3)${menu} Restart Apache ${normal}\n" printf "${menu}**${number} 4)${menu} ssh Frost TomCat Server ${normal}\n" printf "${menu}**${number} 5)${menu} Some other commands${normal}\n" printf "${menu}*********************************************${normal}\n" printf "Please enter a menu option and enter or ${fgred}x to exit. ${normal}" read opt } option_picked(){ msgcolor=`echo "\033[01;31m"` # bold red normal=`echo "\033[00;00m"` # normal white message=${@:-"${normal}Error: No message passed"} printf "${msgcolor}${message}${normal}\n" } clear show_menu while [ $opt != '' ] do if [ $opt = '' ]; then exit; else case $opt in 1) clear; option_picked "Option 1 Picked"; printf "sudo mount /dev/sdh1 /mnt/DropBox/; #The 3 terabyte"; show_menu; ;; 2) clear; option_picked "Option 2 Picked"; printf "sudo mount /dev/sdi1 /mnt/usbDrive; #The 500 gig drive"; show_menu; ;; 3) clear; option_picked "Option 3 Picked"; printf "sudo service apache2 restart"; show_menu; ;; 4) clear; option_picked "Option 4 Picked"; printf "ssh lmesser@ -p 2010"; show_menu; ;; x)exit; ;; \n)exit; ;; *)clear; option_picked "Pick an option from the menu"; show_menu; ;; esac fi done
Не новый ответ как таковой, но так как ответа пока нет, вот несколько советов и хитростей кодирования, как для select, так и для 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
Стоит упомянуть:
Оба цикла будут циклически повторяться до тех пор, пока пользователь явно не выберет Quit (или Cancel для zenity). Это хороший подход для интерактивных меню сценария: после того, как выбор выбран и действие выполнено, меню снова представлено для другого выбора. Если выбор предназначен только для одноразового использования, просто используйте break
после esac
(зенитетность также может быть снижена)
Оба случая case
основаны на индексе, а не на значении. Я думаю, что это легче закодировать и поддерживать
Массив также используется для zenity
подхода.
Опция "Quit" не входит в число исходных, оригинальных опций. Она "добавляется" при необходимости, поэтому ваш массив остается чистым. Afterall, "Quit" все равно не нужен для zenity, пользователь может просто нажать "Cancel" (или закрыть окно), чтобы выйти. Заметьте, как оба используют один и тот же нетронутый массив опций.
PS3
и REPLY
vars могут быть переименованы в not. Выбор
жестко закодирован для использования этих опций. Все остальные переменные в скрипте (opt, options, prompt, title) могут иметь любые имена, при условии, что вы выполните настройки
Используя диалоговое окно
, команда будет выглядеть так:
dialog --clear --backtitle "Backtitle here" --title "Title here" --menu "Choose one of the following options:" 15 40 4 \ 1 "Option 1" \ 2 "Option 2" \ 3 "Option 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, который, кажется, всегда есть в 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
У меня есть еще одна опция, которая представляет собой смесь этих ответов, но что делает это приятным, так это то, что вам нужно нажать только одну клавишу, а затем скрипт продолжает работу благодаря опции -n
чтения. В этом примере мы предлагаем выключить, перезагрузить или просто выйти из сценария с помощью ANS
в качестве нашей переменной, и пользователь должен нажать только E, R, или S. Я также установил по умолчанию, чтобы выйти, так что если ввести нажал, то сценарий будет выходить.
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
Bash fancy menu
Сначала попробуйте, а затем посетите мою страницу для получения подробного описания ... Нет необходимости во внешних библиотеках или программах, таких как dialog или 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
Ответ на этот же вопрос уже есть в serverfault. Решение там использует хлыст .
Так как это нацелено на Ubuntu, вы должны использовать все бэкэндные debconf, которые настроены для использования. Вы можете узнать бэкэнд debconf с:
sudo -s "echo get debconf/frontend | debconf-communicate"
Если в нём написано "dialog", то скорее всего он использует whiptail
или dialog
. На Lucid это хлыст
.
Если это не удаётся, используйте bash "select", как объяснил Деннис Вильямсон.
Предположив, что вы хотите использовать обычное меню сценария оболочки (без причудливого пользовательского интерфейса), проверьте пример меню с http://www.tldp.org/LDP/abs/html/testbranch.html .