首先,OP问题中展示了一个经典的逻辑陷阱:
while [ "$num" == "" ] && [ "$num" != $re ]
这里的问题在于
&&
,它基本上意味着左侧表达式一旦为
false
,整个表达式就为
false
。也就是说,一旦有人输入非空响应,就会中断循环,正则表达式测试就不会被使用。为了解决这个逻辑问题,应该考虑将
&&
更改为
||
,即:
while [ "$num" == "" ] || [ "$num" != $re ]
第二个问题是我们正在测试正则表达式模式的负匹配。因此,这需要分两步完成。首先,我们需要使用
[[ "$num" =~ $re ]]
进行正则表达式测试。然后,我们需要寻找负匹配,即追加一个
!
,如下所示:
while [ "$num" == "" ] || ! [[ "$num" =~ $re ]
许多人发现,在这一步骤中,实际上没有必要测试空字符串。这个边界条件已经被正则表达式本身所覆盖,因此我们优化掉了冗余的测试。现在答案简化为:
while ! [[ "$num" =~ $re ]
除了上述观察,以下是我关于正则表达式的笔记(其中一些观察已经整理自其他答案):
- 可以使用
[[ "$str" =~ regex ]]
语法测试正则表达式
- 正则表达式匹配
$? == 0
(0 == 无错误)
- 正则表达式不匹配
$? == 1
(1 == 错误)
- 引用正则表达式时似乎不起作用。建议使用
[0-9]
而不是"[0-9]"
要实现数字验证,以下模式似乎有效:
str=""
while ! [[ "${str?}" =~ ^[0-9]+$ ]]
do
read -p "enter a number: " str
done
您可以将正则表达式过滤器与常规算术过滤器混合使用,以获得非常好的验证结果:
str=""
while ! [[ "${str?}" =~ ^[0-9]+$ ]] \
|| (( str < 1 || str > 15 ))
do
read -p "enter a number between 1 and 15: " str
done
注意:我使用了${str?}
语法(而不是$str
)进行变量扩展,因为它展示了捕获拼写错误的良好实践。