it-swarm.it

Come posso creare un menu di selezione in uno script Shell?

Sto creando un semplice script bash e voglio creare un menu di selezione al suo interno, in questo modo:

$./script

echo "Choose your option:"

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

E secondo la scelta dell'utente, voglio eseguire diverse azioni. Sono un imbroglione di scripting di Shell, ho cercato sul web alcune risposte, ma non ho ottenuto nulla di veramente concreto.

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

Aggiungi break istruzioni ovunque sia necessario il ciclo select per uscire. Se non viene eseguito un break, l'istruzione select viene ripetuta e il menu viene nuovamente visualizzato.

Nella terza opzione, ho incluso le variabili impostate dall'istruzione select per dimostrare che hai accesso a tali valori. Se lo scegli, genererà:

you chose choice 3 which is Option 3

Puoi vedere che $REPLY contiene la stringa che hai inserito al prompt. Viene utilizzato come indice nell'array ${options[@]} come se l'array fosse basato su 1. La variabile $opt contiene la stringa di quell'indice nell'array.

Nota che le scelte potrebbero essere un semplice elenco direttamente nell'istruzione select in questo modo:

select opt in foo bar baz 'multi Word choice'

ma non puoi mettere un tale elenco in una variabile scalare a causa degli spazi in una delle scelte.

Puoi anche utilizzare il globbing dei file se scegli tra i file:

select file in *.tar.gz
147

Non una nuova risposta di per sé, ma poiché non esiste ancora una risposta accettata, ecco alcuni suggerimenti e trucchi per la codifica, sia per selezionare che per zenità:

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 citare:

  • Entrambi eseguiranno il ciclo fino a quando l'utente non sceglie esplicitamente Esci (o Annulla per zenità). Questo è un buon approccio per i menu di script interattivi: dopo che una scelta è stata selezionata e l'azione è stata eseguita, il menu viene nuovamente presentato per un'altra scelta. Se la scelta è pensata per essere solo una volta, basta usare break dopo esac (anche l'approccio zenity potrebbe essere ulteriormente ridotto)

  • Entrambi case sono basati sull'indice, piuttosto che sul valore. Penso che questo sia più facile da programmare e mantenere

  • L'array viene utilizzato anche per l'approccio zenity.

  • L'opzione "Esci" non è tra le opzioni iniziali e originali. Viene "aggiunto" quando necessario, quindi l'array rimane pulito. Dopotutto, "Esci" non è necessario per Zenity, l'utente può semplicemente fare clic su "Annulla" (o chiudere la finestra) per uscire. Notare come entrambi utilizzano la stessa matrice non trattata di opzioni.

  • PS3 e REPLY vars possono non essere rinominati. select è hardcoded per usare quelli. Tutte le altre variabili nello script (opt, opzioni, Prompt, titolo) possono avere qualsiasi nome desiderato, purché tu faccia le modifiche

56
MestreLion

Usando dialog , il comando sarebbe simile al seguente:

dialog --clear --backtitle "Backtitle here" --title "Title here" --menu "Scegli una delle seguenti opzioni:" 15 40 4\
 1 "Opzione 1"\
 2 "Opzione 2"\
 3 "Opzione 3" 

enter image description here

Mettendolo in uno 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

Puoi usare questo semplice script per creare opzioni

#!/bin/bash 
 echo "seleziona l'operazione ************" 
 echo "1) operazione 1" 
 echo "2) operazione 2 "
 echo" 3) operazione 3 "
 echo" 4) operazione 4 " 
leggi n caso $ n in 1) echo "Hai scelto l'opzione 1" ;; 2) echo "Hai scelto l'opzione 2" ;; 3) echo "Hai scelto l'opzione 3" ;; 4) echo "Hai scelto l'opzione 4" ;; *) Echo "opzione non valida" ;; Esac
14
jibin

Ho un'altra opzione che è una miscela di queste risposte, ma ciò che lo rende bello è che devi solo premere un tasto e quindi lo script continua grazie all'opzione -n di lettura. In questo esempio, stiamo chiedendo di chiudere, riavviare o semplicemente uscire dallo script usando ANS come nostra variabile e l'utente deve solo premere E, R o S. Ho anche impostato il valore predefinito per uscire, quindi se invio viene premuto, quindi lo script verrà chiuso.

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

Poiché questo è indirizzato a Ubuntu, dovresti usare qualunque backconf sia configurato per l'uso. Puoi scoprire il backend debconf con:

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

Se dice "dialog", allora probabilmente usa whiptail o dialog. Su Lucido è whiptail.

Se fallisce, usa bash "select" come spiegato da Dennis Williamson.

7
Li Lo
#!/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} Monta dropbox $ {normal}\n "
 printf "$ {menu} ** $ {numero} 2) $ {menu} Monta unità Gig USB 500 $ {normale}\n" 
 printf "$ {menu} ** $ {numero} 3) $ {menu} Riavvia Apache $ {normal}\n "
 printf" $ {menu} ** $ {numero} 4) $ {menu} ssh Server Tomcat Frost $ {normale}\n "
 printf "$ {menu} ** $ {numero} 5) $ {menu} Alcuni altri comandi $ {normal}\n" 
 printf "$ {menu} ********* ************************************ $ {normal}\n "
 printf" Inserisci un'opzione di menu e inserisci o $ {fgred} x per uscire. $ {Normal} "
 Leggi opt 
} 
 
 Option_picked () {
 msgcolor = `echo"\033 [01; 31m "` # grassetto rosso 
 normal = `echo"\033 [00; 00m "` # messaggio bianco normale 
 = $ {@: - "$ {normal} Errore: nessun messaggio passato"} 
 printf "$ {msgcolor } $ {message} $ {normal}\n "
} 
 
 cancella 
 show_menu 
 mentre [$ opt! = ''] 
 do 
 se [$ opt = '']; quindi 
 esci; 
 altrimenti 
 case $ opt in 
 1) cancella; 
 option_picked "Opzione 1 selezionata"; 
 printf "Sudo mount/dev/sdh1/mnt/DropBox /; #The 3 terabyte"; 
 Show_menu; 
 ;; 
 2) clear; 
 Option_picked "Opzione 2 Picked "; 
 Printf" Sudo mount/dev/sdi1/mnt/usbDrive; #The 500 gig drive "; 
 Show_menu; 
 ;; 
 3) clear; 
 option_picked "Opzione 3 scelta"; 
 printf "Sudo service Apache2 restart"; 
 show_menu; 
 ;; 
 4) clear; 
 option_picked "Opzione 4 selezionata"; 
 printf "ssh lmesser @ -p 2010"; 
 show_menu; 
 ;; 
 x) esci; 
 ;; 
\n) exit; 
 ;; 
 *) cancella; 
 option_picked "Scegli un'opzione da il menu "; 
 show_menu; 
 ;; 
 esac 
 fi 
 fatto
7
Alex Lucard

Ho usato Zenity, che sembra sempre presente su Ubuntu, funziona molto bene e ha molte capacità. Questo è uno schizzo di un possibile 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
6
LazyEchidna

Menu sfizioso

Provalo prima, quindi visita la mia pagina per una descrizione dettagliata ... Non c'è bisogno di librerie o programmi esterni come dialog 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

C'è già la stessa domanda in serverfault ha risposto. La soluzione utilizza coda di cavallo .

2
txwikinger