Shell
方向鍵/進入菜單
如何在 shell 腳本中創建一個菜單,該菜單將顯示 3 個選項,使用者將使用箭頭鍵移動突出顯示游標並按 Enter 鍵選擇一個?
對話框是您想要實現的目標的絕佳工具。這是一個簡單的 3 選擇菜單範例:
dialog --menu "Choose one:" 10 30 3 \ 1 Red \ 2 Green \ 3 Blue
語法如下:
dialog --menu <text> <height> <width> <menu-height> [<tag><item>]
選擇將被發送到
stderr
。這是一個使用 3 種顏色的範例腳本。#!/bin/bash TMPFILE=$(mktemp) dialog --menu "Choose one:" 10 30 3 \ 1 Red \ 2 Green \ 3 Blue 2>$TMPFILE RESULT=$(cat $TMPFILE) case $RESULT in 1) echo "Red";; 2) echo "Green";; 3) echo "Blue";; *) echo "Unknown color";; esac rm $TMPFILE
在 Debian 上,您可以
dialog
通過同名軟體包進行安裝。
bash
這是函式形式的純腳本解決方案select_option
,僅依賴於ANSI 轉義序列和內置的read
.適用於 OSX 上的 Bash 4.2.45。據我所知,在所有環境中可能無法正常工作的時髦部分是
get_cursor_row()
,key_input()
(用於檢測向上/向下鍵)和cursor_to()
功能。#!/usr/bin/env bash # Renders a text based list of options that can be selected by the # user using up, down and enter keys and returns the chosen option. # # Arguments : list of options, maximum of 256 # "opt1" "opt2" ... # Return value: selected index (0 for opt1, 1 for opt2 ...) function select_option { # little helpers for terminal print control and key input ESC=$( printf "\033") cursor_blink_on() { printf "$ESC[?25h"; } cursor_blink_off() { printf "$ESC[?25l"; } cursor_to() { printf "$ESC[$1;${2:-1}H"; } print_option() { printf " $1 "; } print_selected() { printf " $ESC[7m $1 $ESC[27m"; } get_cursor_row() { IFS=';' read -sdR -p $'\E[6n' ROW COL; echo ${ROW#*[}; } key_input() { read -s -n3 key 2>/dev/null >&2 if [[ $key = $ESC[A ]]; then echo up; fi if [[ $key = $ESC[B ]]; then echo down; fi if [[ $key = "" ]]; then echo enter; fi; } # initially print empty new lines (scroll down if at bottom of screen) for opt; do printf "\n"; done # determine current screen position for overwriting the options local lastrow=`get_cursor_row` local startrow=$(($lastrow - $#)) # ensure cursor and input echoing back on upon a ctrl+c during read -s trap "cursor_blink_on; stty echo; printf '\n'; exit" 2 cursor_blink_off local selected=0 while true; do # print options by overwriting the last lines local idx=0 for opt; do cursor_to $(($startrow + $idx)) if [ $idx -eq $selected ]; then print_selected "$opt" else print_option "$opt" fi ((idx++)) done # user key control case `key_input` in enter) break;; up) ((selected--)); if [ $selected -lt 0 ]; then selected=$(($# - 1)); fi;; down) ((selected++)); if [ $selected -ge $# ]; then selected=0; fi;; esac done # cursor position back to normal cursor_to $lastrow printf "\n" cursor_blink_on return $selected }
這是一個範例用法:
echo "Select one option using up/down keys and enter to confirm:" echo options=("one" "two" "three") select_option "${options[@]}" choice=$? echo "Choosen index = $choice" echo " value = ${options[$choice]}"
輸出如下所示,目前選擇的選項使用逆 ansi 著色突出顯示(在降價中很難傳達)。如果需要,可以在
print_selected()
函式中進行調整。Select one option using up/down keys and enter to confirm: [one] two three
**更新:**這是一個
select_opt
包裝上述select_option
函式的小擴展,使其易於在case
語句中使用:function select_opt { select_option "$@" 1>&2 local result=$? echo $result return $result }
使用 3 個文字選項的範例用法:
case `select_opt "Yes" "No" "Cancel"` in 0) echo "selected Yes";; 1) echo "selected No";; 2) echo "selected Cancel";; esac
如果有一些已知條目(在這種情況下是 Yes 和 No),您也可以混合使用,並利用
$?
萬用字元情況的退出程式碼:options=("Yes" "No" "${array[@]}") # join arrays to add some variable array case `select_opt "${options[@]}"` in 0) echo "selected Yes";; 1) echo "selected No";; *) echo "selected ${options[$?]}";; esac