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

87

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

$./script

echo "Choose your option:"

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

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

    
задан Daniel Rodrigues 08.08.2010 в 23:49
источник

11 ответов

94
#!/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 3"
            ;;
        "Quit")
            break
            ;;
        *) echo invalid option;;
    esac
done

Добавьте команды break везде, где вам понадобится цикл select для выхода. Если break не выполняется, оператор select петли и меню повторно отображается.

    
ответ дан Dennis Williamson 09.08.2010 в 01:41
45

Не новый ответ per se , но так как ответа пока нет, вот несколько советов и советов по кодированию, как для выбора, так и для 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 for zenity). Это хороший подход для интерактивных меню сценариев: после выбора и выполнения действия меню снова отображается для другого выбора. Если выбор предназначен только для разового использования, просто используйте break после esac (также можно уменьшить подход zenity)

  • Оба case основаны на индексах, а не на основе значений. Я думаю, что это проще кодировать и поддерживать

  • Массив также используется для подхода zenity .

  • Параметр «Выход» не относится к исходным, оригинальным параметрам. При необходимости он добавляется, поэтому ваш массив остается чистым. В конце концов, «Quit» в любом случае не требуется для zenity, пользователь может просто нажать «Отменить» (или закрыть окно), чтобы выйти. Обратите внимание, как оба используют тот же, нетронутый массив параметров.

  • PS3 и REPLY vars могут быть переименованы not . select жестко запрограммировано для их использования. Все остальные переменные в скрипте (опция, опции, подсказка, заголовок) могут иметь любые имена, если вы выполняете настройки

ответ дан MestreLion 05.08.2011 в 09:40
28

Используя 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
    
ответ дан Alaa Ali 26.08.2015 в 21:33
12

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

#!/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
    
ответ дан jibin 11.08.2011 в 14:11
7

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

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

Если он говорит «диалог», то он скорее всего использует whiptail или dialog . В Lucid это whiptail .

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

    
ответ дан Li Lo 10.08.2010 в 02:30
6

Я использовал 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
    
ответ дан LazyEchidna 05.05.2011 в 03:28
5
#!/bin/sh
show_menu(){
    NORMAL='echo "3[m"'
    MENU='echo "3[36m"' #Blue
    NUMBER='echo "3[33m"' #yellow
    FGRED='echo "3[41m"'
    RED_TEXT='echo "3[31m"'
    ENTER_LINE='echo "3[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='3[01;31m' # bold red
    RESET='3[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 [email protected] -p 2010;
            show_menu;
            ;;

        x)exit;
        ;;

        \n)exit;
        ;;

        *)clear;
        option_picked "Pick an option from the menu";
        show_menu;
        ;;
    esac
fi
done
    
ответ дан Alex Lucard 18.02.2013 в 15:29
4

У меня есть еще один вариант, который представляет собой смесь этих ответов, но приятно то, что вам нужно только нажать один ключ, а затем скрипт продолжается благодаря опции -n для чтения. В этом примере мы запрашиваем выключение, перезагрузку или просто выходим из scrit, используя 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
    
ответ дан HarlemSquirrel 17.05.2015 в 05:58
2

Уже есть тот же вопрос в ответе сервера . В этом решении используется whiptail .

    
ответ дан txwikinger 08.08.2010 в 23:56
2

Приятное меню Bash

Попробуйте сначала, затем зайдите на мою страницу для подробного описания ... Нет необходимости в внешних библиотеках или программах, таких как диалог или зенит ...

#/bin/bash
# by oToGamez
# www.pro-toolz.net

      E='echo -e';e='echo -en';trap "R;exit" 2
    ESC=$( $e "\e")
   TPUT(){ $e "\e[;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
    
ответ дан user360154 19.12.2014 в 10:15
-1

Предполагая, что вы хотите использовать меню сценария с простой оболочкой (нет привлекательного интерфейса), проверьте пример меню из Ссылка .

    
ответ дан João Pinto 09.08.2010 в 00:35