补充Aserre's helpful answer,它解释了您的代码问题并提供了一种有效的解决方法,具有背景信息和允许空输入的通用、可重复使用的自定义select 实现:
背景资料
明确说明:select本身忽略空输入(只需按Enter)并重新提示 - 用户代码甚至没有响应运行。
事实上,select 使用空字符串向用户代码发出信号表明输入了无效选项。
也就是说,如果输出变量 - $opt,在这种情况下 - 在 select 语句中为 empty,则意味着用户键入了无效的选择索引。
输出变量接收所选选项的文本——在本例中为'Yep' 或'Nope'——不是索引 由用户输入。
(相比之下,您的代码检查 $REPLY 而不是输出变量,它包含用户键入的内容,如果有效,是 索引选择,但可能包含额外的前导和尾随空格)。
请注意,如果您不想允许空输入,您可以
只需在提示文本中向用户表明 ^C (Ctrl+C) 可用于中止提示。
通用自定义 select 函数也接受空输入
以下函数与select 的功能非常相似,同时也允许空输入(只需按Enter)。请注意,该函数会拦截无效输入,打印警告并重新提示:
# Custom `select` implementation that allows *empty* input.
# Pass the choices as individual arguments.
# Output is the chosen item, or "", if the user just pressed ENTER.
# Example:
# choice=$(selectWithDefault 'one' 'two' 'three')
selectWithDefault() {
local item i=0 numItems=$#
# Print numbered menu items, based on the arguments passed.
for item; do # Short for: for item in "$@"; do
printf '%s\n' "$((++i))) $item"
done >&2 # Print to stderr, as `select` does.
# Prompt the user for the index of the desired item.
while :; do
printf %s "${PS3-#? }" >&2 # Print the prompt string to stderr, as `select` does.
read -r index
# Make sure that the input is either empty or that a valid index was entered.
[[ -z $index ]] && break # empty input
(( index >= 1 && index <= numItems )) 2>/dev/null || { echo "Invalid selection. Please try again." >&2; continue; }
break
done
# Output the selected item, if any.
[[ -n $index ]] && printf %s "${@: index:1}"
}
你可以这样称呼它:
# Print the prompt message and call the custom select function.
echo "Include audits (default is 'Nope')?"
optionsAudits=('Yep' 'Nope')
opt=$(selectWithDefault "${optionsAudits[@]}")
# Process the selected item.
case $opt in
'Yep') includeAudits=true; ;;
''|'Nope') includeAudits=false; ;; # $opt is '' if the user just pressed ENTER
esac
可选阅读:原始代码的更惯用版本
注意:此代码不能解决问题,但显示了select 语句的更惯用用法;与原始代码不同,如果做出了无效选择,此代码会重新显示提示:
optionsAudits=("Yep" "Nope")
echo "Include audits (^C to abort)?"
select opt in "${optionsAudits[@]}"; do
# $opt being empty signals invalid input.
[[ -n $opt ]] || { echo "What's that? Please try again." >&2; continue; }
break # a valid choice was made, exit the prompt.
done
case $opt in # $opt now contains the *text* of the chosen option
'Yep')
includeAudits=true
;;
'Nope') # could be just `*` in this case.
includeAudits=false
;;
esac
注意: