我是 bash 新手,但我想创建一个脚本,允许用户从选项列表中选择多个选项。
基本上我想要的是类似于下面的例子:
#!/bin/bash
OPTIONS="Hello Quit"
select opt in $OPTIONS; do
if [ "$opt" = "Quit" ]; then
echo done
exit
elif [ "$opt" = "Hello" ]; then
echo Hello World
else
clear
echo bad option
fi
done
Run Code Online (Sandbox Code Playgroud)
(来自http://www.faqs.org/docs/Linux-HOWTO/Bash-Prog-Intro-HOWTO.html#ss9.1)
但是,我的脚本会有更多选项,并且我希望允许选择多个选项。所以像这样:
1) 选项 1
2) 选项 2
3) 选项 3
4) 选项 4
5) 完成
对他们选择的那些有反馈也会很棒,例如在他们已经选择的旁边加号。例如,如果您选择“1”,我想分页清除并重新打印:
1) Option 1 +
2) Option 2
3) Option 3
4) Option 4
5) Done
Run Code Online (Sandbox Code Playgroud)
然后,如果您选择“3”:
1) Option 1 +
2) Option 2
3) Option 3 +
4) Option 4
5) Done
Run Code Online (Sandbox Code Playgroud)
另外,如果他们再次选择 (1) 我希望它“取消选择”该选项:
1) Option 1
2) Option 2
3) Option 3 +
4) Option 4
5) Done
Run Code Online (Sandbox Code Playgroud)
最后,当按下 Done 时,我想要在程序退出之前选择显示的列表,例如,如果当前状态是:
1) Option 1
2) Option 2 +
3) Option 3 +
4) Option 4 +
5) Done
Run Code Online (Sandbox Code Playgroud)
按 5 应该打印:
Option 2, Option 3, Option 4
Run Code Online (Sandbox Code Playgroud)
...脚本终止。
所以我的问题 - 这在 bash 中是否可行,如果可以,是否有人能够提供代码示例?
任何建议将不胜感激。
Den*_*son 40
编辑:
这是使用您问题中的选项的示例脚本:
#!/bin/bash
cmd=(dialog --separate-output --checklist "Select options:" 22 76 16)
options=(1 "Option 1" off # any option can be set to default to "on"
2 "Option 2" off
3 "Option 3" off
4 "Option 4" off)
choices=$("${cmd[@]}" "${options[@]}" 2>&1 >/dev/tty)
clear
for choice in $choices
do
case $choice in
1)
echo "First Option"
;;
2)
echo "Second Option"
;;
3)
echo "Third Option"
;;
4)
echo "Fourth Option"
;;
esac
done
Run Code Online (Sandbox Code Playgroud)
Mes*_*ion 32
如果您认为whiptail
很复杂,这里有一个纯 bash 代码,可以完全满足您的需求。它很短(约 20 行),但对于初学者来说有点神秘。除了为选中的选项显示“+”外,它还为每个用户操作(“无效选项”、“选项 X 已选中”/未选中等)提供反馈。
那就是说,你去!
希望你喜欢......制作它是一个非常有趣的挑战:)
#!/bin/bash
# customize with your own.
options=("AAA" "BBB" "CCC" "DDD")
menu() {
echo "Avaliable options:"
for i in ${!options[@]}; do
printf "%3d%s) %s\n" $((i+1)) "${choices[i]:- }" "${options[i]}"
done
if [[ "$msg" ]]; then echo "$msg"; fi
}
prompt="Check an option (again to uncheck, ENTER when done): "
while menu && read -rp "$prompt" num && [[ "$num" ]]; do
[[ "$num" != *[![:digit:]]* ]] &&
(( num > 0 && num <= ${#options[@]} )) ||
{ msg="Invalid option: $num"; continue; }
((num--)); msg="${options[num]} was ${choices[num]:+un}checked"
[[ "${choices[num]}" ]] && choices[num]="" || choices[num]="+"
done
printf "You selected"; msg=" nothing"
for i in ${!options[@]}; do
[[ "${choices[i]}" ]] && { printf " %s" "${options[i]}"; msg=""; }
done
echo "$msg"
Run Code Online (Sandbox Code Playgroud)
这是一种仅使用 Bash 功能而没有外部依赖关系的方法,可以完全满足您的要求。它标记当前选择并允许您切换它们。
#!/bin/bash
# Purpose: Demonstrate usage of select and case with toggleable flags to indicate choices
# 2013-05-10 - Dennis Williamson
choice () {
local choice=$1
if [[ ${opts[choice]} ]] # toggle
then
opts[choice]=
else
opts[choice]=+
fi
}
PS3='Please enter your choice: '
while :
do
clear
options=("Option 1 ${opts[1]}" "Option 2 ${opts[2]}" "Option 3 ${opts[3]}" "Done")
select opt in "${options[@]}"
do
case $opt in
"Option 1 ${opts[1]}")
choice 1
break
;;
"Option 2 ${opts[2]}")
choice 2
break
;;
"Option 3 ${opts[3]}")
choice 3
break
;;
"Option 4 ${opts[4]}")
choice 4
break
;;
"Done")
break 2
;;
*) printf '%s\n' 'invalid option';;
esac
done
done
printf '%s\n' 'Options chosen:'
for opt in "${!opts[@]}"
do
if [[ ${opts[opt]} ]]
then
printf '%s\n' "Option $opt"
fi
done
Run Code Online (Sandbox Code Playgroud)
对于 ksh,更改函数的前两行:
function choice {
typeset choice=$1
Run Code Online (Sandbox Code Playgroud)
和 shebang 到#!/bin/ksh
.
这是一个 bash 函数,允许用户使用箭头键和空格键选择多个选项,并使用 Enter 确认。它具有类似菜单的良好感觉。我在https://unix.stackexchange.com/a/415155的帮助下编写了它。可以这样调用:
multiselect result "Option 1;Option 2;Option 3" "true;;true"
Run Code Online (Sandbox Code Playgroud)
结果作为数组存储在变量中,名称作为第一个参数提供。最后一个参数是可选的,用于默认选择某些选项。看起来像这样。
function prompt_for_multiselect {
# 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_inactive() { printf "$2 $1 "; }
print_active() { printf "$2 $ESC[7m $1 $ESC[27m"; }
get_cursor_row() { IFS=';' read -sdR -p $'\E[6n' ROW COL; echo ${ROW#*[}; }
key_input() {
local key
IFS= read -rsn1 key 2>/dev/null >&2
if [[ $key = "" ]]; then echo enter; fi;
if [[ $key = $'\x20' ]]; then echo space; fi;
if [[ $key = $'\x1b' ]]; then
read -rsn2 key
if [[ $key = [A ]]; then echo up; fi;
if [[ $key = [B ]]; then echo down; fi;
fi
}
toggle_option() {
local arr_name=$1
eval "local arr=(\"\${${arr_name}[@]}\")"
local option=$2
if [[ ${arr[option]} == true ]]; then
arr[option]=
else
arr[option]=true
fi
eval $arr_name='("${arr[@]}")'
}
local retval=$1
local options
local defaults
IFS=';' read -r -a options <<< "$2"
if [[ -z $3 ]]; then
defaults=()
else
IFS=';' read -r -a defaults <<< "$3"
fi
local selected=()
for ((i=0; i<${#options[@]}; i++)); do
selected+=("${defaults[i]}")
printf "\n"
done
# determine current screen position for overwriting the options
local lastrow=`get_cursor_row`
local startrow=$(($lastrow - ${#options[@]}))
# 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 active=0
while true; do
# print options by overwriting the last lines
local idx=0
for option in "${options[@]}"; do
local prefix="[ ]"
if [[ ${selected[idx]} == true ]]; then
prefix="[x]"
fi
cursor_to $(($startrow + $idx))
if [ $idx -eq $active ]; then
print_active "$option" "$prefix"
else
print_inactive "$option" "$prefix"
fi
((idx++))
done
# user key control
case `key_input` in
space) toggle_option selected $active;;
enter) break;;
up) ((active--));
if [ $active -lt 0 ]; then active=$((${#options[@]} - 1)); fi;;
down) ((active++));
if [ $active -ge ${#options[@]} ]; then active=0; fi;;
esac
done
# cursor position back to normal
cursor_to $lastrow
printf "\n"
cursor_blink_on
eval $retval='("${selected[@]}")'
}
Run Code Online (Sandbox Code Playgroud)