Como posso criar um menu de seleção em um script de shell?

96

Estou criando um script simples e quero criar um menu de seleção, assim:

$./script

echo "Choose your option:"

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

E, de acordo com a escolha do usuário, eu quero que ações diferentes sejam executadas. Eu sou um noob script shell shell, eu procurei na web por algumas respostas, mas não tenho nada realmente concreto.

    
por Daniel Rodrigues 08.08.2010 / 23:49

11 respostas

103

#!/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

Adicione as instruções break sempre que precisar que o loop select saia. Se um break não for executado, a instrução select entrará em loop e o menu será exibido novamente.

Na terceira opção, incluí as variáveis que são definidas pela instrução select para demonstrar que você tem acesso a esses valores. Se você escolher, a saída será:

you chose choice 3 which is Option 3

Você pode ver que $REPLY contém a string digitada no prompt. É usado como um índice na matriz ${options[@]} como se a matriz fosse baseada em 1. A variável $opt contém a string desse índice na matriz.

Observe que as opções podem ser uma lista simples diretamente na instrução select , como esta:

select opt in foo bar baz 'multi word choice'

mas você não pode colocar essa lista em uma variável escalar por causa dos espaços em uma das opções.

Você também pode usar globalização de arquivos se estiver escolhendo entre arquivos:

select file in *.tar.gz
    
por Dennis Williamson 09.08.2010 / 01:41
47

Não é uma nova resposta per se , mas como não há uma resposta aceita ainda, aqui estão algumas dicas e truques de codificação, para seleção e 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

Vale a pena mencionar:

  • Ambos serão executados até que o usuário escolha explicitamente Sair (ou Cancelar para zenidade). Essa é uma boa abordagem para menus de scripts interativos: depois que uma opção é selecionada e a ação executada, o menu é apresentado novamente para outra escolha. Se a escolha se destina a ser apenas uma vez, use apenas break após esac (a abordagem de zenidade também pode ser ainda mais reduzida)

  • Os dois case são baseados em índice, em vez de baseados em valor. Acho que é mais fácil codificar e manter

  • A matriz também é usada para a abordagem zenity .

  • A opção "Sair" não está entre as opções iniciais e originais. É "adicionado" quando necessário, para que sua matriz fique limpa. Afinal, "Quit" não é necessário para zenity de qualquer maneira, o usuário pode simplesmente clicar em "Cancelar" (ou fechar a janela) para sair. Observe como ambos usam a mesma matriz de opções sem intenções.

  • PS3 e REPLY vars podem não ser renomeados. select é codificado para usá-los. Todas as outras variáveis no script (opt, opções, prompt, título) podem ter qualquer nome desejado, desde que você faça os ajustes

por MestreLion 05.08.2011 / 09:40
32

Usando dialog , o comando ficaria assim:

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"

Colocando em um script:

#!/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
    
por Alaa Ali 26.08.2015 / 21:33
13

Você pode usar este script simples para criar opções

#!/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
    
por jibin 11.08.2011 / 14:11
7

Como este é direcionado ao Ubuntu, você deve usar o debend de backend configurado para uso. Você pode descobrir o backend do debconf com:

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

Se disser "caixa de diálogo", é provável que use whiptail ou dialog . No Lucid é whiptail .

Se isso falhar, use bash "select" como explicado por Dennis Williamson.

    
por Li Lo 10.08.2010 / 02:30
6

Eu usei o Zenity, que sempre aparece no Ubuntu, funciona muito bem e tem muitos recursos. Este é um esboço de um possível menu:

#! /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
    
por LazyEchidna 05.05.2011 / 03:28
6
#!/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 lmesser@ -p 2010;
            show_menu;
            ;;

        x)exit;
        ;;

        \n)exit;
        ;;

        *)clear;
        option_picked "Pick an option from the menu";
        show_menu;
        ;;
    esac
fi
done
    
por Alex Lucard 18.02.2013 / 15:29
4

Eu tenho mais uma opção que é uma mistura dessas respostas, mas o que a torna legal é que você só precisa pressionar uma tecla e o script continua, graças à opção -n da leitura. Neste exemplo, estamos solicitando o desligamento, reinicialização ou simplesmente sair do scrit usando ANS como nossa variável e o usuário só precisa pressionar E, R ou S. Também defino o padrão para sair, portanto, se enter for pressionado então o script irá sair.

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
    
por HarlemSquirrel 17.05.2015 / 05:58
2

Já existe a mesma pergunta em serverfault respondida. A solução lá usa whiptail .

    
por txwikinger 08.08.2010 / 23:56
2

Menu chique de fantasia

Teste primeiro e depois visite a minha página para descrição detalhada ... Não há necessidade de bibliotecas externas ou programas como diálogo ou 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[;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
    
por user360154 19.12.2014 / 10:15
-1

Supondo que você queira usar um menu de script de shell simples (sem interface de usuário sofisticada), consulte o exemplo de menu em link .

    
por João Pinto 09.08.2010 / 00:35