我决定为验证 while 循环创建 fn ,我将在整个代码中重复使用它:
loopFN() {
while true; do
if [ "$1" == "null" ] || ([ "$2" == "phone number" ] && ! [[ "$1" =~ $phone_regex ]]); then
printf 'enter a valid %s\n' "$2"
read
$1=$REPLY
else
break
fi
done
}
我这样称呼它:
local number="null"
loopFN "$number" "phone number"
我的电话号码正则表达式是:
phone_regex="^[0-9]{3}-[0-9]{3}-[0-9]{4}"
我得到的错误是:
./newmenu.sh: line 27: null=dasd: command not found
其中“dasd”是我在提示时输入的内容
重用 while 循环是不好的做法吗?我应该重写它多少次吗?或者我的语法有问题吗?
我猜问题就在这里(错误引用的第 27 行):
$1=$REPLY
我试图设置传入 fn 的变量,在本例中为 $number,我最初的想法是它不起作用,因为 var 是本地的,但我删除了 local 关键字,错误仍然存在
编辑:
我根据建议添加了一些更改:
loopFN() {
while true; do
if [[ $1 = null ]]; then
printf>&2 'enter a valid %s\n' "$2"
IFS= read -r "$1"
elif [[ $1 = null || ( $2 = 'phone number' && ! $1 =~ $phone_regex ) ]]; then
printf>&2 "enter a valid phone number\n"
IFS= read -r "$1"
else
break
fi
done
}
答案1
$1=$REPLY
=
不被理解为变量赋值,因为( )的左边$1
不是有效的变量名,因此它仅被视为命令参数或命令参数列表(因为$1
并且$REPLY
未加引号,所以受 split+glob 的约束)它被视为命令名称。
你需要:
eval "$1=\$REPLY"
要要求 shellcontents_of_$1=$REPLY
作为 shell 代码进行计算,并假设 的内容$1
是有效的变量名称,则会将 的值分配$REPLY
给相应的变量(如果$1
是reboot;foo
,则显然会重新启动)。
在这里你还可以这样做:
IFS= read -r "$1"
它将使用作为参数read
的内容进行调用,并且不关心也无法知道该变量名是按字面传递还是扩展的结果。$1
read
这仍然是一个命令注入漏洞(就像when $1
is一样foo[`reboot`]
)。
无论如何,读取一行的语法是IFS= read -r line
, 不是。read line
另请注意(...)
,在 Korn 风格[[...]]
构造之外启动一个子 shell,您的
if [ "$1" == "null" ] || ([ "$2" == "phone number" ] && ! [[ "$1" =~ $phone_regex ]])
更应该是:
if [[ $1 = null || ( $2 = 'phone number' && ! $1 =~ $phone_regex ) ]]
如果$1
是一个变量名,那就$1 =~ $phone_regex
没什么意义了。电话号码很少是有效的变量名称。
如果您打算检查名称为 的变量的内容$1
,那么您可以使用${!1}
bash 语法来取消引用变量,或者按照 ChatGPT 的建议,将 ksh93 样式的名称引用与较新版本的 bash 一起使用。
请注意,无论如何,您需要传递给函数的是变量名称 ( number
) 而不是值 ( )。$number
用户提示和交互通常会转到 stderr,stdout 被保留用于命令产生的实际输出,其他东西可能想要重用/后处理。
printf>&2 'enter a valid %s\n' "$2"
特别是对于bash
shell,您可以使用-p
其read
内置选项来发出p
rompt(它也会发送到 stderr):
IFS= read -rp "Enter a valid $2: " "$1"
而在大多数其他类似 Korn 的 shell 中,语法是:
IFS= read -r "$1?Enter a valid $2: "
如果该函数旨在输入电话号码,反复询问直到用户输入有效的电话号码,并将其返回到第一个参数中提供名称的变量中,然后使用 bash 特定的语法,它看起来像:
input_phone_number() {
local -n _var_name="$1"
local _regex='^[0123456789]{3}-[0123456789]{3}-[0123456789]{4,}$'
until
IFS= read -rp 'Please enter a valid phone number: ' _var_name ||
return # return failure upon EOF
[[ $_var_name =~ $_regex ]]
do
echo>&2 'Not a valid phone number, try again.'
done
}
input_phone_number number || exit
(使用[0123456789]
而不是[0-9]
as[0-9]
可以匹配任何内容,并在末尾和开头锚定正则表达式)。
对于input
采用输入类型和验证正则表达式作为参数的通用函数:
input() {
local -n _var_name="$1"
local _type="$2" _regex="$3"
until
IFS= read -rp "Please enter a valid $_type: " _var_name ||
return # return failure upon EOF
[[ $_var_name =~ $_regex ]]
do
echo>&2 "Not a valid $_type, try again."
done
}
input number \
'phone number' \
'^[0123456789]{3}-[0123456789]{3}-[0123456789]{4,}$' || exit
请注意_
局部变量中的前缀,以便用户可以执行input type type '^(good|bad)$'
例如操作,而不会导致$type
局部变量与他们想要返回的用户$type
变量发生冲突。