it-swarm-vi.com

Làm cách nào để tạo menu chọn trong tập lệnh Shell?

Tôi đang tạo một tập lệnh bash đơn giản và tôi muốn tạo một menu chọn trong đó, như thế này:

$./script

echo "Choose your option:"

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

Và theo lựa chọn của người dùng, tôi muốn các hành động khác nhau được thực thi. Tôi là một boo Shell scripting noob, tôi đã tìm kiếm trên mạng một số câu trả lời, nhưng không có gì thực sự cụ thể.

122
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

Thêm câu lệnh break bất cứ nơi nào bạn cần vòng lặp select để thoát. Nếu một break không được thực hiện, các vòng lặp câu lệnh select và menu sẽ được hiển thị lại.

Trong tùy chọn thứ ba, tôi đã bao gồm các biến được đặt bởi câu lệnh select để chứng minh rằng bạn có quyền truy cập vào các giá trị đó. Nếu bạn chọn nó, nó sẽ xuất ra:

you chose choice 3 which is Option 3

Bạn có thể thấy rằng $REPLY chứa chuỗi bạn đã nhập tại Nhắc. Nó được sử dụng như một chỉ mục vào mảng ${options[@]} như thể mảng dựa trên 1. Biến $opt chứa chuỗi từ chỉ mục đó trong mảng.

Lưu ý rằng các lựa chọn có thể là một danh sách đơn giản trực tiếp trong câu lệnh select như thế này:

select opt in foo bar baz 'multi Word choice'

nhưng bạn không thể đặt một danh sách như vậy trong một biến vô hướng vì các khoảng trắng trong một trong các lựa chọn.

Bạn cũng có thể sử dụng tệp toàn cầu nếu bạn chọn trong số các tệp:

select file in *.tar.gz
137
Dennis Williamson

Không phải là một câu trả lời mới per se, nhưng vì chưa có câu trả lời nào được chấp nhận, nên đây là một vài mẹo và thủ thuật mã hóa, cho cả lựa chọn và sự thoải mái:

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

Đáng nói:

  • Cả hai sẽ lặp cho đến khi người dùng chọn rõ ràng Thoát (hoặc Hủy vì sự thoải mái). Đây là một cách tiếp cận tốt cho các menu script tương tác: sau khi lựa chọn được chọn và thực hiện hành động, menu sẽ được trình bày lại cho lựa chọn khác. Nếu sự lựa chọn chỉ là một lần duy nhất, chỉ cần sử dụng break sau esac (cách tiếp cận tiện ích cũng có thể được giảm thêm)

  • Cả case đều dựa trên chỉ mục, thay vì dựa trên giá trị. Tôi nghĩ rằng điều này là dễ dàng hơn để mã hóa và duy trì

  • Mảng cũng được sử dụng cho cách tiếp cận zenity.

  • Tùy chọn "Thoát" không nằm trong số các tùy chọn ban đầu, ban đầu. Nó được "thêm" khi cần, vì vậy mảng của bạn sạch sẽ. Dù sao đi nữa, "Thoát" không cần thiết cho sự thoải mái, người dùng chỉ cần nhấp vào "Hủy" (hoặc đóng cửa sổ) để thoát. Lưu ý cách cả hai sử dụng cùng một mảng tùy chọn chưa được chạm tới.

  • PS3REPLY vars có thể không được đổi tên. select được mã hóa cứng để sử dụng chúng. Tất cả các biến khác trong tập lệnh (opt, tùy chọn, Nhắc, tiêu đề) có thể có bất kỳ tên nào bạn muốn, miễn là bạn thực hiện các điều chỉnh

54
MestreLion

Sử dụng dialogNAME _ , lệnh sẽ như thế này:

hộp thoại --clear --backtitle "Backtitle here" --title "Title here" --menu "Chọn một trong các tùy chọn sau:" 15 40 4\[.__.] 1 "Tùy chọn 1"\[.__.] 2 "Tùy chọn 2"\[.__.] 3 "Tùy chọn 3" [.__.]

enter image description here

Đưa nó vào một kịch bản:

#!/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
52
Alaa Ali

Bạn có thể sử dụng tập lệnh đơn giản này để tạo tùy chọn

#!/bin/bash [.__.] echo "chọn thao tác ************" [.__.] echo "1) thao tác 1" [.__.] echo "2) hoạt động 2 "[.__.] echo" 3) hoạt động 3 "[.__.] echo" 4) hoạt động 4 " 
[.__.] đọc n [.__.] trường hợp $ n trong [.__.] 1) echo "Bạn đã chọn Tùy chọn 1" ;; [.__.] 2) echo "Bạn đã chọn Tùy chọn 2" ;; 3) echo "Bạn đã chọn Tùy chọn 3" ;; [.__.] 4) echo "Bạn đã chọn Tùy chọn 4" ;; [.__.] *) Echo "tùy chọn không hợp lệ" ;; [.__.] Esac [.__.]
14
jibin

Vì mục tiêu này được nhắm mục tiêu tại Ubuntu, bạn nên sử dụng bất kỳ nội dung phụ trợ nào được cấu hình để sử dụng. Bạn có thể tìm hiểu phần phụ trợ gỡ lỗi với:

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

Nếu nó nói "hộp thoại" thì có khả năng nó sử dụng whiptail hoặc dialog. Trên Lucid, đó là whiptail.

Nếu thất bại, hãy sử dụng bash "select" như được giải thích bởi Dennis Williamson.

7
Li Lo
#!/bin/sh [.__.] show_menu () {[.__.] normal = `echo"\033 [m "` [.___ .__.] number = `echo"\033 [33m "` #yellow [.__.] bgred = `echo"\033 [41m "` [.__. .__.] printf "\ n $ {menu} ******/TÌM KIẾM ******* $ {normal}\n "[.__.] printf" $ {menu} ** $ {number} 1) $ {menu} Mount dropbox $ {normal}\n "[.___ ] printf "$ {menu} ** $ {number} 2) $ {menu} Gắn USB 500 Gig Drive $ {normal}\n" [.__.] printf "$ {menu} ** $ {number} 3) $ {menu} Khởi động lại Apache $ {normal}\n "[.__.] printf" $ {menu} ** $ {number} 4) $ {menu} ssh Frost Tomcat Server $ {normal}\n "[.___ .] printf "$ {menu} ** $ {number} 5) $ {menu} Một số lệnh khác $ {normal}\n" [.__.] printf "$ {menu} ********* ******/TÌM KIẾM Vui lòng nhập một tùy chọn menu và nhập hoặc $ {fgred} x để thoát. $ {Bình thường} "[.__.] Đọc opt [.__.]} [.__.] [.__.] Option_picky () {
 dircolor = `echo"\033 [01; 31m "` # đậm màu đỏ [.__.] normal = `echo"\033 [00; 00m "` # normal trắng [.__.] message = $ {@: - "$ {normal} Lỗi: Không có tin nhắn nào được chuyển"} [.__.] printf "$ {dircolor } $ {message} $ {normal}\n "[.__.]} [.__.] [.__.] xóa [.__.] show_menu [.__.] trong khi [$ opt! = ''] [ .__.] làm [.__.] nếu [$ opt = '']; sau đó [.__.] thoát; [.__.] khác [.__.] case $ opt in [.__.] 1) rõ ràng; [.__.] tùy chọn_picky "Tùy chọn 1 được chọn"; [.__.] printf "Sudo mount/dev/sdh1/mnt/DropBox /; #The 3 terabyte"; [.___] Show_menu; [.__.] ;; 2 Đã chọn "; [.__.] Printf" Sudo mount/dev/sdi1/mnt/usbDrive; #The 500 gig drive "; [.___ rõ ràng; [.__.] tùy chọn_picky "Tùy chọn 3 đã chọn"; [.__.] printf "Dịch vụ Sudo Apache2 khởi động lại"; [.___ [.__.] tùy chọn_picky "Tùy chọn 4 đã chọn"; [.__.] printf "ssh lmesser @ -p 2010"; [.___ [.__.] ;; [.__.]\n) thoát; [.__.] ;; [.__.] *) rõ ràng; [.__.] tùy chọn_picky "Chọn một tùy chọn từ menu "; [.__.] show_menu; [.__.] ;; [.__.] esac [.__.] fi [.__.] xong
7
Alex Lucard

Tôi có thêm một tùy chọn là hỗn hợp của những câu trả lời này, nhưng điều làm cho nó hay là bạn chỉ cần nhấn một phím và sau đó tập lệnh tiếp tục nhờ vào tùy chọn đọc -n. Trong ví dụ này, chúng tôi đang nhắc tắt máy, khởi động lại hoặc đơn giản là thoát tập lệnh bằng cách sử dụng ANS làm biến của chúng tôi và người dùng chỉ phải nhấn E, R hoặc S. Tôi cũng đặt mặc định để thoát vì vậy nếu nhấn enter thì nhấn kịch bản sẽ thoát.

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

Tôi đã sử dụng Zenity, dường như luôn có trong Ubuntu, hoạt động rất tốt và có nhiều khả năng. Đây là một bản phác thảo của một menu có thể:

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

Thực đơn ưa thích của Bash

Hãy dùng thử trước, sau đó truy cập trang của tôi để biết mô tả chi tiết ... Không cần thư viện hoặc chương trình bên ngoài như hộp thoại hoặc tiện nghi ...

#/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ó câu hỏi tương tự trong serverfault đã trả lời. Giải pháp ở đó sử dụng whiptail .

2
txwikinger