在我的bash脚本中,我经常提示用户提供y / n答案。因为我经常在一个脚本中多次使用它,所以我想要一个函数来检查用户输入是否为Yes / No的变体,然后将此答案清除为“y”或“n”。像这样:
yesno(){
temp=""
if [[ "$1" =~ ^([Yy](es|ES)?|[Nn][Oo]?)$ ]] ; then
temp=$(echo "$1" | tr '[:upper:]' '[:lower:]' | sed 's/es//g' | sed 's/no//g')
break
else
echo "$1 is not a valid answer."
fi
}
然后我想使用如下函数:
while read -p "Do you want to do this? " confirm; do # Here the user types "YES"
yesno $confirm
done
if [[ $confirm == "y" ]]; then
[do something]
fi
基本上,我想将第一个参数的值更改为$confirm
的值,这样当我退出yesno
函数时,$confirm
是“y”或“ N”。
我尝试在set -- "$temp"
函数中使用yesno
,但我无法让它工作。
答案 0 :(得分:1)
您可以通过输出新值并覆盖调用者中的变量来实现。
yesno() {
if [[ "$1" =~ ^([Yy](es|ES)?|[Nn][Oo]?)$ ]] ; then
local answer=${1,,}
echo "${answer::1}"
else
echo "$1 is not a valid answer." >&2
echo "$1" # output the original value
return 1 # indicate failure in case the caller cares
fi
}
confirm=$(yesno "$confirm")
但是,我建议采用更直接的方法:让函数执行提示和循环。将所有重复的逻辑移到里面。然后呼叫站点非常简单。
confirm() {
local prompt=$1
local reply
while true; do
read -p "$prompt" reply
case ${reply,,} in
y*) return 0;;
n*) return 1;;
*) echo "$reply is not a valid answer." >&2;;
esac
done
}
if confirm "Do you want to do this? "; then
# Do it.
else
# Don't do it.
fi
(${reply,,}
是一种将$reply
转换为小写的bash-ism。)
答案 1 :(得分:1)
您可以使用Bash的 nameref 属性(需要Bash 4.3或更高版本),如下所示:
#!/bin/bash
yesno () {
# Declare arg as reference to argument provided
declare -n arg=$1
local re1='(y)(es)?'
local re2='(n)o?'
# Set to empty and return if no regex matches
[[ ${arg,,} =~ $re1 ]] || [[ ${arg,,} =~ $re2 ]] || { arg= && return; }
# Assign "y" or "n" to reference
arg=${BASH_REMATCH[1]}
}
while read -p "Prompt: " confirm; do
yesno confirm
echo "$confirm"
done
示例测试运行如下:
Prompt: YES
y
Prompt: nOoOoOo
n
Prompt: abc
Prompt:
表达式锚定在开头,因此yessss
等也都计算在内。如果不需要,可以添加结束锚($
)。
如果两个表达式都不匹配,则将字符串设置为空。