我想暂停shell脚本中的输入,并提示用户进行选择。标准的是、否或取消类型问题。如何在典型的bash提示符中完成此操作?
当前回答
受到@Mark和@Myrdin的回答的启发,我创建了一个通用提示的函数
uniprompt(){
while true; do
echo -e "$1\c"
read opt
array=($2)
case "${array[@]}" in *"$opt"*) eval "$3=$opt";return 0;; esac
echo -e "$opt is not a correct value\n"
done
}
这样使用:
unipromtp "Select an option: (a)-Do one (x)->Do two (f)->Do three : " "a x f" selection
echo "$selection"
其他回答
仅单个按键
这里有一个更长但可重复使用的模块化方法:
返回0=yes和1=no无需按enter键-仅需一个字符可以按enter键接受默认选择可以禁用默认选项以强制选择适用于zsh和bash。
按enter键时默认为“否”
请注意,N是大写的。此处按enter键,接受默认值:
$ confirm "Show dangerous command" && echo "rm *"
Show dangerous command [y/N]?
还要注意,[y/N]?已自动追加。默认的“no”被接受,因此不会有任何回音。
重新提示,直到给出有效响应:
$ confirm "Show dangerous command" && echo "rm *"
Show dangerous command [y/N]? X
Show dangerous command [y/N]? y
rm *
按回车键时默认为“是”
请注意,Y是大写的:
$ confirm_yes "Show dangerous command" && echo "rm *"
Show dangerous command [Y/n]?
rm *
上面,我刚刚按了回车键,所以命令运行了。
输入时无默认值-需要y或n
$ get_yes_keypress "Here you cannot press enter. Do you like this [y/n]? "
Here you cannot press enter. Do you like this [y/n]? k
Here you cannot press enter. Do you like this [y/n]?
Here you cannot press enter. Do you like this [y/n]? n
$ echo $?
1
这里,返回了1或false。请注意,使用此较低级别的函数,您需要提供自己的[y/n]?促使
Code
# Read a single char from /dev/tty, prompting with "$*"
# Note: pressing enter will return a null string. Perhaps a version terminated with X and then remove it in caller?
# See https://unix.stackexchange.com/a/367880/143394 for dealing with multi-byte, etc.
function get_keypress {
local REPLY IFS=
>/dev/tty printf '%s' "$*"
[[ $ZSH_VERSION ]] && read -rk1 # Use -u0 to read from STDIN
# See https://unix.stackexchange.com/q/383197/143394 regarding '\n' -> ''
[[ $BASH_VERSION ]] && </dev/tty read -rn1
printf '%s' "$REPLY"
}
# Get a y/n from the user, return yes=0, no=1 enter=$2
# Prompt using $1.
# If set, return $2 on pressing enter, useful for cancel or defualting
function get_yes_keypress {
local prompt="${1:-Are you sure [y/n]? }"
local enter_return=$2
local REPLY
# [[ ! $prompt ]] && prompt="[y/n]? "
while REPLY=$(get_keypress "$prompt"); do
[[ $REPLY ]] && printf '\n' # $REPLY blank if user presses enter
case "$REPLY" in
Y|y) return 0;;
N|n) return 1;;
'') [[ $enter_return ]] && return "$enter_return"
esac
done
}
# Credit: http://unix.stackexchange.com/a/14444/143394
# Prompt to confirm, defaulting to NO on <enter>
# Usage: confirm "Dangerous. Are you sure?" && rm *
function confirm {
local prompt="${*:-Are you sure} [y/N]? "
get_yes_keypress "$prompt" 1
}
# Prompt to confirm, defaulting to YES on <enter>
function confirm_yes {
local prompt="${*:-Are you sure} [Y/n]? "
get_yes_keypress "$prompt" 0
}
作为单行命令的朋友,我使用了以下命令:
while [ -z $prompt ]; do read -p "Continue (y/n)?" choice;case "$choice" in y|Y ) prompt=true; break;; n|N ) exit 0;; esac; done; prompt=;
以长格式编写,其工作原理如下:
while [ -z $prompt ];
do read -p "Continue (y/n)?" choice;
case "$choice" in
y|Y ) prompt=true; break;;
n|N ) exit 0;;
esac;
done;
prompt=;
您需要:
Bash内置命令(即便携式)检查TTY默认答案超时彩色问题
一小条
do_xxxx=y # In batch mode => Default is Yes
[[ -t 0 ]] && # If TTY => Prompt the question
read -n 1 -p $'\e[1;32m
Do xxxx? (Y/n)\e[0m ' do_xxxx # Store the answer in $do_xxxx
if [[ $do_xxxx =~ ^(y|Y|)$ ]] # Do if 'y' or 'Y' or empty
then
xxxx
fi
解释
[[-t 0]]&&read…=>如果TTY,调用命令读取read-n 1=>等待一个字符$'\e[1;32m…\e[0m'=>绿色打印(绿色很好,因为在白色/黑色背景上都可以阅读)[[$do_xxxx=~^(y|y|)$]]=>bash正则表达式
超时=>默认答案为否
do_xxxx=y
[[ -t 0 ]] && { # Timeout 5 seconds (read -t 5)
read -t 5 -n 1 -p $'\e[1;32m
Do xxxx? (Y/n)\e[0m ' do_xxxx || # read 'fails' on timeout
do_xxxx=n ; } # Timeout => answer No
if [[ $do_xxxx =~ ^(y|Y|)$ ]]
then
xxxx
fi
这个问题有很多很好的答案,但从我看来,没有一个是我的理想,那就是:
简单一点,只需要几行外壳使用单个y/n键(无需按enter键)如果只按回车键,则默认为yes也可以使用大写的Y/N
这是我的版本,它具有这些财产:
read -n1 -p "Continue? (Y/n) " confirm
if ! echo $confirm | grep '^[Yy]\?$'; then
exit 1
fi
如果要在两个分支上运行代码,可以修改该条件,使其仅在“yes”上运行(只需删除if语句中的!)或添加else。
针对其他人:
您不需要在BASH4中指定大小写,只需使用',,'使var小写即可。此外,我强烈不喜欢将代码放在读取块内,获取结果并在读取块IMO外处理它。还包括一个“q”表示退出IMO。最后,为什么键入“yes”只需使用-n1并按y。
示例:用户可以按y/n和q退出。
ans=''
while true; do
read -p "So is MikeQ the greatest or what (y/n/q) ?" -n1 ans
case ${ans,,} in
y|n|q) break;;
*) echo "Answer y for yes / n for no or q for quit.";;
esac
done
echo -e "\nAnswer = $ans"
if [[ "${ans,,}" == "q" ]] ; then
echo "OK Quitting, we will assume that he is"
exit 0
fi
if [[ "${ans,,}" == "y" ]] ; then
echo "MikeQ is the greatest!!"
else
echo "No? MikeQ is not the greatest?"
fi