it-swarm-es.com

¿Cómo puedo crear un menú de selección en un script de Shell?

Estoy creando un script bash simple y quiero crear un menú de selección en él, como este:

$./script

echo "Choose your option:"

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

Y según la elección del usuario, quiero que se ejecuten diferentes acciones. Soy un novato de scripts de Shell, busqué en la web algunas respuestas, pero no obtuve nada realmente concreto.

129
Daniel Rodrigues
#!/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

Agregue las sentencias break donde necesite el bucle select para salir. Si no se realiza una break, la instrucción select se repite y se vuelve a mostrar el menú.

En la tercera opción, incluí variables establecidas por la instrucción select para demostrar que tiene acceso a esos valores. Si lo elige, generará:

you chose choice 3 which is Option 3

Puede ver que $REPLY contiene la cadena que ingresó en la solicitud. Se utiliza como índice en la matriz ${options[@]} como si la matriz estuviera basada en 1. La variable $opt contiene la cadena de ese índice en la matriz.

Tenga en cuenta que las opciones podrían ser una lista simple directamente en la declaración select como esta:

select opt in foo bar baz 'multi Word choice'

pero no puede poner dicha lista en una variable escalar debido a los espacios en una de las opciones.

También puede usar el bloqueo de archivos si elige entre archivos:

select file in *.tar.gz
147

No es una nueva respuesta per se , pero dado que aún no hay una respuesta aceptada, aquí hay algunos consejos y trucos de codificación, tanto para select como para 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 la pena mencionar:

  • Ambos se repetirán hasta que el usuario elija explícitamente Salir (o Cancelar por zenity). Este es un buen enfoque para los menús de guiones interactivos: después de seleccionar una opción y realizar una acción, el menú se presenta nuevamente para otra opción. Si la opción es solo una vez, solo use break después de esac (el enfoque de zenity también podría reducirse aún más)

  • Ambos case están basados ​​en índices, en lugar de estar basados ​​en valores. Creo que esto es más fácil de codificar y mantener

  • La matriz también se utiliza para el enfoque zenity.

  • La opción "Salir" no se encuentra entre las opciones iniciales originales. Se "agrega" cuando es necesario, para que su matriz se mantenga limpia. Después de todo, "Salir" no es necesario para zenity de todos modos, el usuario puede simplemente hacer clic en "Cancelar" (o cerrar la ventana) para salir. Observe cómo ambos usan la misma matriz de opciones intacta.

  • PS3 y REPLY vars pueden no cambiar el nombre. select está codificado para usarlos. Todas las demás variables en el script (opt, options, Prompt, title) pueden tener los nombres que desee, siempre que realice los ajustes

56
MestreLion

Usando dialogNAME _ , el comando se vería así:

cuadro de diálogo --clear --backtitle "Backtitle here" --title "Title here" --menu "Elija una de las siguientes opciones:" 15 40 4\
 1 "Opción 1"\
 2 "Opción 2"\
 3 "Opción 3" 

enter image description here

Poniéndolo en un 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
54
Alaa Ali

Puede usar este script simple para crear opciones

#!/bin/bash 
 echo "seleccione la operación ************" 
 echo "1) operación 1" 
 echo "2) operación 2 "
 eco" 3) operación 3 "
 eco" 4) operación 4 " 
leer n caso $ n en 1) echo "Usted eligió la Opción 1" ;; 2) echo "Usted eligió la Opción 2" ;; 3) echo "Usted eligió la Opción 3" ;; 4) echo "Usted eligió la Opción 4" ;; *) Echo "opción no válida" ;; Esac
14
jibin

Tengo una opción más que es una mezcla de estas respuestas, pero lo que la hace agradable es que solo necesita presionar una tecla y luego el script continúa gracias a la opción -n de lectura. En este ejemplo, le pedimos que apague, reinicie o simplemente salga del script usando ANS como nuestra variable y el usuario solo tiene que presionar E, R o S. También configuro el valor predeterminado para salir, así que si ingresa se presiona y luego el script saldrá.

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
8
HarlemSquirrel

Dado que esto está dirigido a Ubuntu, debe usar cualquier debconf backend configurado para usar. Puede encontrar el backend de debconf con:

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

Si dice "diálogo", entonces probablemente use whiptail o dialog. En Lucid es whiptail.

Si eso falla, use bash "select" como lo explicó Dennis Williamson.

7
Li Lo
#!/bin/sh 
 show_menu () {
 normal = `echo"\033 [m "` 
 menu = `echo"\033 [36m "` #Blue 
 número = `echo"\033 [33m "` #amarillo 
 bgred = `echo"\033 [41m "` 
 fgred = `echo"\033 [31m "` 
 printf "\ n $ {menu} ************************************** ******* $ {normal}\n "
 printf" $ {menu} ** $ {number} 1) $ {menu} Montar dropbox $ {normal}\n "
 printf "$ {menu} ** $ {number} 2) $ {menu} Montar unidad USB 500 Gig $ {normal}\n" 
 printf "$ {menu} ** $ {number} 3) $ {menu} Reiniciar Apache $ {normal}\n "
 printf" $ {menu} ** $ {number} 4) $ {menu} ssh Servidor Frost Tomcat $ {normal}\n "
 printf "$ {menu} ** $ {number} 5) $ {menu} Algunos otros comandos $ {normal}\n" 
 printf "$ {menu} ********* ************************************ $ {normal}\n "
 printf" Ingrese una opción de menú e ingrese o $ {fgred} x para salir. $ {Normal} "
 Read opt 
} 
 
 Option_picked () {
 msgcolor = `echo"\033 [01; 31m "` # negrita rojo 
 normal = `echo"\033 [00; 00m "` # blanco normal 
 mensaje = $ {@: - "$ {normal} Error: No se pasó ningún mensaje"} 
 printf "$ {msgcolor } $ {mensaje} $ {normal}\n "
} 
 
 borrar 
 show_menu 
 mientras [$ opt! = ''] 
 do 
 if [$ opt = '']; luego 
 salir; 
 más 
 caso $ opt en 
 1) borrar; 
 option_picked "Opción 1 elegida"; 
 printf "Sudo mount/dev/sdh1/mnt/DropBox /; #The 3 terabyte"; 
 Show_menu; 
 ;; 
 2) clear; 
 Option_picked "Opción 2 Elegido "; 
 Printf" Sudo mount/dev/sdi1/mnt/usbDrive; #The 500 gig drive "; 
 Show_menu; 
 ;; 
 3) clear; 
 option_picked "Opción 3 elegida"; 
 printf "Sudo service Apache2 restart"; 
 show_menu; 
 ;; 
 4) clear; 
 option_picked "Opción 4 elegida"; 
 printf "ssh lmesser @ -p 2010"; 
 show_menu; 
 ;; 
 x) salir; 
 ;; 
\n) salir; 
 ;; 
 *) borrar; 
 option_picked "Seleccionar una opción de el menú "; 
 show_menu; 
 ;; 
 esac 
 fi 
 hecho
7
Alex Lucard

He usado Zenity, que siempre parece estar en Ubuntu, funciona muy bien y tiene muchas capacidades. Este es un boceto de un posible menú:

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

Menú sofisticado de Bash

Pruébelo primero, luego visite mi página para obtener una descripción detallada ... No necesita bibliotecas o programas externos como diálogo o 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
5
user360154

Ya hay la misma pregunta en serverfault respondida. La solución allí usa whiptail .

2
txwikinger