Я создаю простой сценарий bash и хочу создать в нем меню выбора, например:
$./script
echo "Choose your option:"
1) Option 1
2) Option 2
3) Option 3
4) Quit
И, по выбору пользователя, я хочу, чтобы выполнялись разные действия. Я noob, пишущий в bash, я искал ответы в Интернете, но ничего конкретного не получил.
Не новый ответ как таковой , но, поскольку еще нет принятого ответа, вот несколько советов и рекомендаций по кодированию, как для избранных, так и для 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
и REPLY
переменные могут не быть переименованы. select
жестко запрограммирован для их использования. Все остальные переменные в сценарии (opt, options, prompt, title) могут иметь любые имена, которые вы хотите, при условии, что вы выполняете настройки
#!/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
break
, который выходит из цикла select
. Вы можете добавить break
где угодно. В руководстве по Bash говорится: «Команды выполняются после каждого выбора до тех пор, пока не будет выполнена команда прерывания, после чего команда выбора завершается».
– Eric Dieckman
08.12.2015, 05:31
./test.sh: line 9: syntax error near unexpected token
«Вариант 1» ./test.sh: строка 9: `& quot; Вариант 1 & quot;) '`
– serhio
09.12.2016, 02:59
PS3
- приглашение для команды select
. Он используется автоматически и не требует явных ссылок. PS3
и select
документация.
– Smart Killer
01.12.2017, 08:55
Так как это нацелено на Ubuntu, вы должны использовать любой бэкэнд debconf, настроенный для использования. Вы можете найти бэкэнд debconf с помощью:
sudo -s "echo get debconf/frontend | debconf-communicate"
Если он говорит «диалог», то он, вероятно, использует whiptail
или dialog
. На Lucid это whiptail
.
Если это не поможет, используйте bash «select», как объяснил Деннис Уильямсон.
Вы можете использовать этот простой скрипт для создания опций
#!/bin/bash
echo "select the operation ************ 1)operation 1 2)operation 2 3)operation 3 4)operation 4 "
read n
case $n in
1) commands for opn 1;;
2) commands for opn 2;;
3) commands for opn 3;;
4) commands for opn 4;;
*) invalid option;;
esac
. Используя dialog
, команда будет выглядеть так:
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
TERMINAL=$(tty)
в начало моего скрипта, а затем в определении переменной CHOICE
я изменил 2>&1 >/dev/tty
на 2>&1 >$TERMINAL
, чтобы избежать проблем с перенаправлением, если скрипт запускался в другом терминальный контекст.
– Ronnie Overby
13.06.2018, 03:37
У меня есть еще один вариант, который представляет собой смесь этих ответов, но что делает его приятным, так это то, что вам нужно всего лишь нажать одну клавишу, а затем сценарий продолжается благодаря опции -n
read. В этом примере мы предлагаем выключить, перезагрузить или просто выйти из скрипта, используя 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
Модное меню 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
#!/bin/sh show_menu(){ NORMAL=`echo "\033[m"` MENU=`echo "\033[36m"` #Blue NUMBER=`echo "\033[33m"` #yellow FGRED=`echo "\033[41m"` RED_TEXT=`echo "\033[31m"` ENTER_LINE=`echo "\033[33m"` echo -e "${MENU}*********************************************${NORMAL}" echo -e "${MENU}**${NUMBER} 1)${MENU} Mount dropbox ${NORMAL}" echo -e "${MENU}**${NUMBER} 2)${MENU} Mount USB 500 Gig Drive ${NORMAL}" echo -e "${MENU}**${NUMBER} 3)${MENU} Restart Apache ${NORMAL}" echo -e "${MENU}**${NUMBER} 4)${MENU} ssh Frost TomCat Server ${NORMAL}" echo -e "${MENU}**${NUMBER} 5)${MENU} ${NORMAL}" echo -e "${MENU}*********************************************${NORMAL}" echo -e "${ENTER_LINE}Please enter a menu option and enter or ${RED_TEXT}enter to exit. ${NORMAL}" read opt } function option_picked() { COLOR='\033[01;31m' # bold red RESET='\033[00;00m' # normal white MESSAGE=${@:-"${RESET}Error: No message passed"} echo -e "${COLOR}${MESSAGE}${RESET}" } clear show_menu while [ opt != '' ] do if [[ $opt = "" ]]; then exit; else case $opt in 1) clear; option_picked "Option 1 Picked"; sudo mount /dev/sdh1 /mnt/DropBox/; #The 3 terabyte menu; ;; 2) clear; option_picked "Option 2 Picked"; sudo mount /dev/sdi1 /mnt/usbDrive; #The 500 gig drive menu; ;; 3) clear; option_picked "Option 3 Picked"; sudo service apache2 restart; show_menu; ;; 4) clear; option_picked "Option 4 Picked"; ssh lmesser@ -p 2010; show_menu; ;; x)exit; ;; \n)exit; ;; *)clear; option_picked "Pick an option from the menu"; show_menu; ;; esac fi done
$
отсутствует в переменной $opt
в выражении while
. Оператор if
является избыточным. Несовместимый отступ. Использование menu
в некоторых местах, где это должно быть 'show_menu .
show_menu`, может быть помещено в верхнюю часть цикла вместо повторения в каждом case
. Несовместимый отступ. Смешивание использовать одинарные квадратные скобки и двойные. Использование жестко закодированных последовательностей ANSI вместо tput
. Использование имен всех заглавных букв не рекомендуется. FGRED
следует назвать bgred
. Использование обратных галочек вместо $()
. Определение функции должно быть согласованным и не использовать ...
– Martin Redington
30.05.2018, 09:57
\n
никогда не будет выполнен. Возможно больше.
– JimmyB
30.05.2018, 10:01
Я использовал 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
Уже есть тот же вопрос в ответе serverfault . Решение там использует хлыст .
Предполагая, что вы хотите использовать простое меню сценария оболочки (без необычного пользовательского интерфейса), посмотрите пример меню из http://www.tldp.org/LDP/abs/html/testbranch.html .
case
для версииselect
, которую вы используете для версииzenity
:case "$opt" in . . . "${options[0]}" ) . . .
(вместо$REPLY
и индексов1
,2
и3
]). – saille 30.05.2018, 09:40$REPLY
, индексами и значениями. – Guy 01.06.2018, 09:28