将参数中命名的变量更改为bash函数
在我的bash脚本中,我经常提示用户输入y/n答案。由于我经常在一个脚本中多次使用此选项,因此我希望有一个函数来检查用户输入是否是Yes/No的某个变体,然后将此答案清除为“y”或“n”。大概是这样的:将参数中命名的变量更改为bash函数,bash,function,unix,Bash,Function,Unix,在我的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' |
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
}
Prompt: YES
y
Prompt: nOoOoOo
n
Prompt: abc
Prompt:
然后,我想使用以下函数:
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
#!/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
基本上,我想将第一个参数的值更改为$confirm
的值,这样当我退出yesno
函数时,$confirm
要么是“y”要么是“n”
我尝试在
yesno
函数中使用set--“$temp”
,但无法使其工作。您可以通过输出新值并覆盖调用者中的变量来实现
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。)您可以使用bash的nameref属性(需要bash 4.3或更高版本),如下所示:
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
#!/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
示例测试运行如下所示:
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
}
Prompt: YES
y
Prompt: nOoOoOo
n
Prompt: abc
Prompt:
表达式锚定在开始处,因此yesss
等。所有表达式也都计算在内。如果不需要,可以添加端锚($
)
如果两个表达式都不匹配,字符串将设置为空。这似乎是一个X-Y问题——问题是关于建议的解决方案,而不是OP实际想要使用该解决方案解决的问题。被接受的答案在外部范围内根本不会改变,
“$1”
,因此其他人将其作为搜索结果查找时可能会感到困惑——也许应该对问题进行编辑,以便更紧密地描述真实/直接的问题?…也就是说,基于原始标题,我原以为OP想知道如何更改$1
本身,而不是$1
内容中命名的变量的值。为了将来参考,应该注意${reply,,}
仅在Bash 4或newer@HubertL艾维尔·高文:谢谢你的提示。你知道如何用bash 3明智地完成吗?