bash:在 "select" 提示符下按回车时从大小写中选择默认值
bash: choose default from case when enter is pressed in a "select" prompt
我在这样的 bash 脚本中提示问题:
optionsAudits=("Yep" "Nope")
echo "Include audits?"
select opt in "${optionsAudits[@]}"; do
case $REPLY in
1) includeAudits=true; break ;;
2) includeAudits=false; break ;;
"\n") echo "You pressed enter"; break ;; # <--- doesn't work
*) echo "What's that?"; exit;;
esac
done
如何在按下 enter 时 select 默认选项? "\n"
大小写没有捕捉到回车键。
更新的答案:
echo "Include audits? 1) Yep, 2) Nope"
read ans
case $ans in
Yep|1 ) echo "yes"; includeAudits=true; v=1 ;;
Nope|2 ) echo "no"; includeAudits=false; v=2 ;;
"" ) echo "default - yes"; includeAudits=true; v=1 ;;
* ) echo "Whats that?"; exit ;;
esac
这接受 "Yep"
或 "1"
或 "enter"
到 select 是,接受 "Nope"
或 "2"
表示否,并且扔掉其他任何东西。它还将 v 设置为 1 或 2,具体取决于用户想要是还是否。
您的问题是由于 select
将忽略空输入。对于您的情况,read
会更合适,但您将失去 select
提供的用于自动创建菜单的实用程序。
要模仿 select
的行为,您可以这样做:
#!/bin/bash
optionsAudits=("Yep" "Nope")
while : #infinite loop. be sure to break out of it when a valid choice is made
do
i=1
echo "Include Audits?"
#we recreate manually the menu here
for o in "${optionsAudits[@]}"; do
echo "$i) $o"
let i++
done
read reply
#the user can either type the option number or copy the option text
case $reply in
"1"|"${optionsAudits[0]}") includeAudits=true; break;;
"2"|"${optionsAudits[1]}") includeAudits=false; break;;
"") echo "empty"; break;;
*) echo "Invalid choice. Please choose an existing option number.";;
esac
done
echo "choice : \"$reply\""
为了补充 ,它解释了您的代码问题并提供了有效的解决方法,其中包含 背景信息和通用的、可重复使用的自定义 select
实现,允许空输入:
背景资料
明确说明:select
本身 忽略空输入(只需按 Enter) 和 只是重新提示 - 用户代码甚至没有到达 运行 作为响应。
事实上,select
使用空字符串向用户代码发出信号,表明输入了 无效 选择。
也就是说,如果输出变量 - $opt
,在本例中 - 在 select
语句中是 empty,这意味着输入了无效的选择索引用户。
输出变量接收所选选项的 text - 在本例中为 'Yep'
或 'Nope'
- 不是用户输入的 index。
(相比之下,您的代码检查 $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
注意:
case
语句被移出 select
语句,因为后者现在保证只能进行有效输入。
case
语句测试输出变量($opt
)而不是原始用户输入($REPLY
),并且该变量包含选项 text,而不是它的 index。
这将满足您的要求。
options=("option 1" "option 2");
while :
do
echo "Select your option:"
i=1;
for opt in "${options[@]}"; do
echo "$i) $opt";
let i++;
done
read reply
case $reply in
"1"|"${options[0]}"|"")
doSomething1();
break;;
"2"|"${options[1]}")
doSomething2();
break;;
*)
echo "Invalid choice. Please choose 1 or 2";;
esac
done
假设您的默认选项是 Yep
:
#!/bin/bash
optionsAudits=("Yep" "Nope")
while : #infinite loop. be sure to break out of it when a valid choice is made
do
i=1
echo "Include Audits?: "
#we recreate manually the menu here
for o in "${optionsAudits[@]}"; do
echo " $i) $o"
let i++
done
read -rp "Audit option: " -iYep
#the user can either type the option number or copy the option text
case $REPLY in
"1"|"${optionsAudits[0]}") includeAudits=true; break;;
"2"|"${optionsAudits[1]}") includeAudits=false; break;;
"") includeAudits=true; break;;
*) echo "Invalid choice. Please choose an existing option number.";;
esac
done
echo "choice : \"$REPLY\""
echo "includeAudits : \"$includeAudits\""
注意到行:
read -rp "Audit option: " -eiYep
我还把 $reply
调高到 $REPLY
以便更好地进行案件判决。
按下 ENTER 后的输出现在如下所示:
Include Audits?:
1) Yep
2) Nope
Audit option: Yep
choice : ""
includeAudits : "true"
#
作为对 select
的增强,read -eiYep
将预先向输入缓冲区提供 Yep
默认值。
将默认值置于前面的唯一缺点是必须按几次退格键才能输入自己的答案。
我在这样的 bash 脚本中提示问题:
optionsAudits=("Yep" "Nope")
echo "Include audits?"
select opt in "${optionsAudits[@]}"; do
case $REPLY in
1) includeAudits=true; break ;;
2) includeAudits=false; break ;;
"\n") echo "You pressed enter"; break ;; # <--- doesn't work
*) echo "What's that?"; exit;;
esac
done
如何在按下 enter 时 select 默认选项? "\n"
大小写没有捕捉到回车键。
更新的答案:
echo "Include audits? 1) Yep, 2) Nope"
read ans
case $ans in
Yep|1 ) echo "yes"; includeAudits=true; v=1 ;;
Nope|2 ) echo "no"; includeAudits=false; v=2 ;;
"" ) echo "default - yes"; includeAudits=true; v=1 ;;
* ) echo "Whats that?"; exit ;;
esac
这接受 "Yep"
或 "1"
或 "enter"
到 select 是,接受 "Nope"
或 "2"
表示否,并且扔掉其他任何东西。它还将 v 设置为 1 或 2,具体取决于用户想要是还是否。
您的问题是由于 select
将忽略空输入。对于您的情况,read
会更合适,但您将失去 select
提供的用于自动创建菜单的实用程序。
要模仿 select
的行为,您可以这样做:
#!/bin/bash
optionsAudits=("Yep" "Nope")
while : #infinite loop. be sure to break out of it when a valid choice is made
do
i=1
echo "Include Audits?"
#we recreate manually the menu here
for o in "${optionsAudits[@]}"; do
echo "$i) $o"
let i++
done
read reply
#the user can either type the option number or copy the option text
case $reply in
"1"|"${optionsAudits[0]}") includeAudits=true; break;;
"2"|"${optionsAudits[1]}") includeAudits=false; break;;
"") echo "empty"; break;;
*) echo "Invalid choice. Please choose an existing option number.";;
esac
done
echo "choice : \"$reply\""
为了补充 select
实现,允许空输入:
背景资料
明确说明:select
本身 忽略空输入(只需按 Enter) 和 只是重新提示 - 用户代码甚至没有到达 运行 作为响应。
事实上,select
使用空字符串向用户代码发出信号,表明输入了 无效 选择。
也就是说,如果输出变量 - $opt
,在本例中 - 在 select
语句中是 empty,这意味着输入了无效的选择索引用户。
输出变量接收所选选项的 text - 在本例中为 'Yep'
或 'Nope'
- 不是用户输入的 index。
(相比之下,您的代码检查 $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
注意:
case
语句被移出select
语句,因为后者现在保证只能进行有效输入。case
语句测试输出变量($opt
)而不是原始用户输入($REPLY
),并且该变量包含选项 text,而不是它的 index。
这将满足您的要求。
options=("option 1" "option 2");
while :
do
echo "Select your option:"
i=1;
for opt in "${options[@]}"; do
echo "$i) $opt";
let i++;
done
read reply
case $reply in
"1"|"${options[0]}"|"")
doSomething1();
break;;
"2"|"${options[1]}")
doSomething2();
break;;
*)
echo "Invalid choice. Please choose 1 or 2";;
esac
done
假设您的默认选项是 Yep
:
#!/bin/bash
optionsAudits=("Yep" "Nope")
while : #infinite loop. be sure to break out of it when a valid choice is made
do
i=1
echo "Include Audits?: "
#we recreate manually the menu here
for o in "${optionsAudits[@]}"; do
echo " $i) $o"
let i++
done
read -rp "Audit option: " -iYep
#the user can either type the option number or copy the option text
case $REPLY in
"1"|"${optionsAudits[0]}") includeAudits=true; break;;
"2"|"${optionsAudits[1]}") includeAudits=false; break;;
"") includeAudits=true; break;;
*) echo "Invalid choice. Please choose an existing option number.";;
esac
done
echo "choice : \"$REPLY\""
echo "includeAudits : \"$includeAudits\""
注意到行:
read -rp "Audit option: " -eiYep
我还把 $reply
调高到 $REPLY
以便更好地进行案件判决。
按下 ENTER 后的输出现在如下所示:
Include Audits?:
1) Yep
2) Nope
Audit option: Yep
choice : ""
includeAudits : "true"
#
作为对 select
的增强,read -eiYep
将预先向输入缓冲区提供 Yep
默认值。
将默认值置于前面的唯一缺点是必须按几次退格键才能输入自己的答案。