bash中的shell脚本在while循环中使用正则表达式

时间:2015-01-24 14:02:03

标签: regex bash ubuntu

您好我尝试验证用户输入不为空并且是数字或带小数

re='^[0-9]+$'
while [ "$num" == "" ] && [[ "$num" ~= $re ]]
do 
echo "Please enter the price : "
read num
done

我能够在第一个条件下顺利运行。当我添加第二个条件时,我的程序无法运行。

---- EDIT ----------

好的,我尝试更改并运行程序。但是当我输入一个数字时,它仍然会提示输入。

re='^[0-9]+$'
while [ "$num" == "" ] && [ "$num" != $re ]
do 
echo "Please enter the price : "
read num
done

3 个答案:

答案 0 :(得分:2)

regualar表达式可以与运算符=~一起使用,而非~=,就像您使用它一样。

  

可以使用另外的二元运算符=〜   在dence as = =和!=之前。当它被使用时,在右边的字符串
  运算符被视为扩展正则表达式并匹配   因此(如正则表达式(3))。如果是字符串,则返回值为0   匹配模式,否则为1。如果是正则表达式   在语法上不正确,条件表达式的返回值是   2.如果启用了shell选项nocasematch,则执行匹配   不考虑字母字符的情况。任何一部分   可以引用模式以强制引用的部分匹配为a   串。必须处理正则表达式中的括号表达式   仔细,因为正常的引用字符之间失去了意义   括号。如果模式存储在shell变量中,则引用   变量扩展强制整个模式匹配为字符串。   子字符串与常规中带括号的子表达式匹配   表达式保存在数组变量BASH_REMATCH中。元素   索引为0的BASH_REMATCH是与之匹配的字符串部分   整个正则表达式。索引为n的BASH_REMATCH元素为   匹配第n个带括号的子表达式的字符串部分。

考虑这些例子(0真/匹配,1假/不匹配)

re=^[0-9]+; [[ "1" =~ ${re} ]]; echo $? # 0
re=^[0-9]+; [[ "a" =~ ${re} ]]; echo $? # 1
re=^[0-9]+; [[ "a1" =~ ${re} ]]; echo $? # 1
re=^[0-9]+; [[ "1a" =~ ${re} ]]; echo $? # 0 because it starts with a number

使用这个来检查数字

re=^[0-9]+$; [[ "1a" =~ ${re} ]]; echo $? # 1 because checked up to the end
re=^[0-9]+$; [[ "11" =~ ${re} ]]; echo $? # 0 because all nums

更新:如果您只想检查用户是否输入了一个数字,请将上述经验教训与您的需求结合起来。我认为你的条件不合适。也许这个片段完全解决了你的问题。

#!/bin/bash
re=^[0-9]+$
while ! [[ "${num}" =~ ${re} ]]; do
    echo "enter num:"
    read num
done

如果${num}不是!),则此代码段仅请求输入。在第一次运行期间${num}未设置,因此它不适合至少一个数字,${num}然后计算为空字符串。之后它只包含输入的输入。

答案 1 :(得分:1)

你的错误很简单;变量不能同时为空和数字。也许你的意思是||“或”而不是&&“和”。

您也可以使用glob模式执行此操作。

while true; do
  read -r -p "Enter a price: " num
  case $num in
    "" | *[!.0-9]* | *.*.*) echo invalid ;;
    *) break;;
esac

答案 2 :(得分:0)

首先,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)进行变量扩展,因为它演示了捕获错别字的好习惯。