如何在bash中实现多菜单DRY编程
How to implement DRY programming with multiple menus in bash
我的 bash 脚本中有选择菜单,我很好奇是否有一种方法可以简化和压缩菜单而不重复我自己。我尝试了很多不同的方法都无济于事,有没有人知道压缩这段代码的好方法:
PS3="some menu"
options=("option1" "option2" "option3" "exit")
select opt in "${options[@]}"
do
case $opt in
"option1")
something
;;
"option2")
something else
;;
"option3")
something different
;;
"exit")
;;
*) echo "invalid option $REPLY";;
esac
read -p "Press Enter to continue"
clear
return 1
done
PS3="some menu 2"
options=("option 1" "option2" "exit")
select opt in "${options[@]}"
do
case $opt in
"option 1")
something
;;
"option 2")
something
;;
"exit")
exit
;;
*) echo "invalid option $REPLY";;
esac
read -p "Press Enter to continue"
clear
return 1
done
我想压缩这段代码而不在我的代码中重复多个菜单。
放在一个函数里调用两次,像这样:
#!/usr/bin/env bash
prompt() {
local opt
local -A isExpected
local -a options
PS3=""
shift
options=()
for opt; do
isExpected["$opt"]=1
options+=("$opt")
done
isExpected["exit"]=1
options+=("exit")
select opt in "${options[@]}"
do
if (( "${isExpected[$opt]}" )); then
case $opt in
"option 1")
something
;;
"option 2")
something
;;
"option 3")
something
;;
"exit")
;;
*) printf 'invalid option "%s"\n' "$REPLY" >&2;;
esac
else
printf 'unexpected option "%s"\n' "$opt" >&2
fi
read -r -p "Press Enter to continue"
clear
return 1
done
}
prompt "some menu" "option 1" "option 2" "option 3"
prompt "some menu 2" "option 1" "option 2"
显然,您可以将所有常用选项移动到 prompt()
中,就像我为 "exit"
所做的那样。如果出现的选项顺序无关紧要,那么您可以去掉 isExpected[]
,只使用一个关联数组来保存 options
并使用 ${!options[@]}"
访问 select。
您可以使用分派 table,将选项文本映射到该选项的函数。这需要 bash 版本 4.4+ 才能使用 local -n
namerefs
fn_a1() { echo "do something here for option a1"; }
fn_a2() { echo "do something here for option a2"; }
fn_a3() { echo "do something here for option a3"; }
fn_b1() { echo "do something here for option b1"; }
fn_b2() { echo "do something here for option b2"; }
prompt() {
local PS3=": "
local -n _options= _dispatch=
select opt in "${_options[@]}"; do
if [[ -v _dispatch["$opt"] ]]; then
"${_dispatch[$opt]}"
break
fi
done
}
declare -A dispatch_table
declare -a options
options=( "option a1" "option a2" "option a3" exit )
dispatch_table=(
["option a1"]=fn_a1
["option a2"]=fn_a2
["option a3"]=fn_a3
["exit"]=exit
)
prompt "some menu" options dispatch_table
options=( "option b1" "option b2" exit )
dispatch_table=(
["option b1"]=fn_b1
["option b2"]=fn_b2
["exit"]=exit
)
prompt "some menu 2" options dispatch_table
我将选项作为一个单独的数组发送,这样我就可以控制菜单的顺序:遍历关联数组的键没有固有顺序。
我的 bash 脚本中有选择菜单,我很好奇是否有一种方法可以简化和压缩菜单而不重复我自己。我尝试了很多不同的方法都无济于事,有没有人知道压缩这段代码的好方法:
PS3="some menu"
options=("option1" "option2" "option3" "exit")
select opt in "${options[@]}"
do
case $opt in
"option1")
something
;;
"option2")
something else
;;
"option3")
something different
;;
"exit")
;;
*) echo "invalid option $REPLY";;
esac
read -p "Press Enter to continue"
clear
return 1
done
PS3="some menu 2"
options=("option 1" "option2" "exit")
select opt in "${options[@]}"
do
case $opt in
"option 1")
something
;;
"option 2")
something
;;
"exit")
exit
;;
*) echo "invalid option $REPLY";;
esac
read -p "Press Enter to continue"
clear
return 1
done
我想压缩这段代码而不在我的代码中重复多个菜单。
放在一个函数里调用两次,像这样:
#!/usr/bin/env bash
prompt() {
local opt
local -A isExpected
local -a options
PS3=""
shift
options=()
for opt; do
isExpected["$opt"]=1
options+=("$opt")
done
isExpected["exit"]=1
options+=("exit")
select opt in "${options[@]}"
do
if (( "${isExpected[$opt]}" )); then
case $opt in
"option 1")
something
;;
"option 2")
something
;;
"option 3")
something
;;
"exit")
;;
*) printf 'invalid option "%s"\n' "$REPLY" >&2;;
esac
else
printf 'unexpected option "%s"\n' "$opt" >&2
fi
read -r -p "Press Enter to continue"
clear
return 1
done
}
prompt "some menu" "option 1" "option 2" "option 3"
prompt "some menu 2" "option 1" "option 2"
显然,您可以将所有常用选项移动到 prompt()
中,就像我为 "exit"
所做的那样。如果出现的选项顺序无关紧要,那么您可以去掉 isExpected[]
,只使用一个关联数组来保存 options
并使用 ${!options[@]}"
访问 select。
您可以使用分派 table,将选项文本映射到该选项的函数。这需要 bash 版本 4.4+ 才能使用 local -n
namerefs
fn_a1() { echo "do something here for option a1"; }
fn_a2() { echo "do something here for option a2"; }
fn_a3() { echo "do something here for option a3"; }
fn_b1() { echo "do something here for option b1"; }
fn_b2() { echo "do something here for option b2"; }
prompt() {
local PS3=": "
local -n _options= _dispatch=
select opt in "${_options[@]}"; do
if [[ -v _dispatch["$opt"] ]]; then
"${_dispatch[$opt]}"
break
fi
done
}
declare -A dispatch_table
declare -a options
options=( "option a1" "option a2" "option a3" exit )
dispatch_table=(
["option a1"]=fn_a1
["option a2"]=fn_a2
["option a3"]=fn_a3
["exit"]=exit
)
prompt "some menu" options dispatch_table
options=( "option b1" "option b2" exit )
dispatch_table=(
["option b1"]=fn_b1
["option b2"]=fn_b2
["exit"]=exit
)
prompt "some menu 2" options dispatch_table
我将选项作为一个单独的数组发送,这样我就可以控制菜单的顺序:遍历关联数组的键没有固有顺序。