Как я могу создать меню выбора в сценарии оболочки?

Я создаю простой сценарий bash и хочу создать в нем меню выбора, например:

$./script

echo "Choose your option:"

1) Option 1  
2) Option 2  
3) Option 3  
4) Quit  

И, по выбору пользователя, я хочу, чтобы выполнялись разные действия. Я noob, пишущий в bash, я искал ответы в Интернете, но ничего конкретного не получил.

156
задан 13 December 2017 в 19:35

11 ответов

#!/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
177
ответ дан 13 December 2017 в 19:35

Вы можете использовать этот простой сценарий для создания опций

#!/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
16
ответ дан 13 December 2017 в 19:35
#!/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
8
ответ дан 13 December 2017 в 19:35

Не новый ответ как таковой, но так как ответа пока нет, вот несколько советов и хитростей кодирования, как для 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) могут иметь любые имена, при условии, что вы выполните настройки

61
ответ дан 13 December 2017 в 19:35

Используя диалоговое окно , команда будет выглядеть так:

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"

enter image description here

Помещение ее в сценарий:

#!/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
79
ответ дан 13 December 2017 в 19:35

Я использовал 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
6
ответ дан 13 December 2017 в 19:35

У меня есть еще одна опция, которая представляет собой смесь этих ответов, но что делает это приятным, так это то, что вам нужно нажать только одну клавишу, а затем скрипт продолжает работу благодаря опции -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
13
ответ дан 13 December 2017 в 19:35

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
6
ответ дан 13 December 2017 в 19:35

Ответ на этот же вопрос уже есть в serverfault. Решение там использует хлыст .

3
ответ дан 13 December 2017 в 19:35

Так как это нацелено на Ubuntu, вы должны использовать все бэкэндные debconf, которые настроены для использования. Вы можете узнать бэкэнд debconf с:

sudo -s "echo get debconf/frontend | debconf-communicate"

Если в нём написано "dialog", то скорее всего он использует whiptail или dialog. На Lucid это хлыст .

Если это не удаётся, используйте bash "select", как объяснил Деннис Вильямсон.

7
ответ дан 13 December 2017 в 19:35

Предположив, что вы хотите использовать обычное меню сценария оболочки (без причудливого пользовательского интерфейса), проверьте пример меню с http://www.tldp.org/LDP/abs/html/testbranch.html .

-1
ответ дан 13 December 2017 в 19:35

Другие вопросы по тегам:

Похожие вопросы: