简体   繁体   English

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

[英]shell script in bash using regex in while loop

Hi i am try to validate user inputs to be not empty and is a number or with decimal嗨,我正在尝试验证用户输入不为空,并且是数字或小数

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

I was able to run smooth with just the 1st condition.我能够在第一个条件下顺利运行。 When i add 2nd condition my program couldn't run.当我添加第二个条件时,我的程序无法运行。

----EDIT---------- - - 编辑 - - - - -

Ok i try changing and the program run.好的,我尝试更改并运行程序。 But when i enter a number it still prompting for input.但是当我输入一个数字时,它仍然提示输入。

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

regualar expression can be used with the operator =~ not ~= like you used it.正则表达式可以与运算符=~一起使用,而不是像您使用的那样~=

An additional binary operator, =~, is available, with the same prece dence as == and !=.可以使用额外的二元运算符 =~,其优先级与 == 和 != 相同。 When it is used, the string to the right of使用时,右边的字符串
the operator is considered an extended regular expression and matched accordingly (as in regex(3)).运算符被视为扩展的正则表达式并相应地匹配(如在 regex(3) 中)。 The return value is 0 if the string matches the pattern, and 1 otherwise.如果字符串与模式匹配,则返回值为 0,否则为 1。 If the regular expression is syntactically incorrect, the conditional expression's return value is 2. If the shell option nocasematch is enabled, the match is performed without regard to the case of alphabetic characters.如果正则表达式在语法上不正确,则条件表达式的返回值为 2。如果启用了 shell 选项 nocasematch,则执行匹配时不考虑字母字符的大小写。 Any part of the pattern may be quoted to force the quoted portion to be matched as a string.可以引用模式的任何部分以强制引用部分作为字符串进行匹配。 Bracket expressions in regular expressions must be treated carefully, since normal quoting characters lose their meanings between brackets.必须谨慎对待正则表达式中的括号表达式,因为正常的引用字符在括号之间失去了它们的含义。 If the pattern is stored in a shell variable, quoting the variable expansion forces the entire pattern to be matched as a string.如果模式存储在 shell 变量中,则引用变量扩展会强制将整个模式作为字符串进行匹配。 Substrings matched by parenthesized subexpressions within the regular expression are saved in the array variable BASH_REMATCH.正则表达式中括号内子表达式匹配的子字符串保存在数组变量 BASH_REMATCH 中。 The element of BASH_REMATCH with index 0 is the portion of the string matching the entire regular expression.索引为 0 的 BASH_REMATCH 元素是与整个正则表达式匹配的字符串部分。 The element of BASH_REMATCH with index n is the portion of the string matching the nth parenthesized subexpression.索引为 n 的 BASH_REMATCH 元素是与第 n 个带括号的子表达式匹配的字符串部分。

consider theese examples (0 true/match, 1 false/no match)考虑这些示例(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

use this one to check for 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

UPDATE: If you just want to check if the user inputs a number combine the lesson learned above with your needs.更新:如果您只想检查用户是否输入了一个数字,请将上面学到的经验与您的需求结合起来。 i think your conditions do not fit.我觉得你的条件不适合。 perhaps this snippet solves your issue completely.也许这个片段完全解决了你的问题。

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

This snippet just requests input if ${num} is NOT ( ! ) a number.如果${num}不是 ( ! ) 数字,则此代码段仅请求输入。 During the first run ${num} is not set so it will not fit at least one number, ${num} then evaluates to an empty string.在第一次运行期间${num}未设置,因此它至少不适合一个数字,然后${num}评估为空字符串。 Afterwards it just contains the input entered.之后它只包含输入的输入。

Your error is simple;你的错误很简单; the variable can't be both empty and a number at the same time.变量不能同时为空和数字。 Maybe you mean ||也许你的意思是|| "or" instead of && "and". “或”而不是&& “和”。

You can do this with glob patterns as well.您也可以使用 glob 模式来做到这一点。

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

First off, there is the classic logic trap demonstrated in the OP's question:首先,在 OP 的问题中展示了经典的逻辑陷阱:

while [ "$num" == "" ] && [ "$num" != $re ]

The issue here is the && which pretty much means the moment the left expression is false , the entire expression is false .这里的问题是&&这几乎意味着当左表达式为false ,整个表达式为false ie the moment somebody types a non empty response, it breaks the loop and the regular expression test is never used.即当有人输入一个非空的响应时,它会中断循环并且从不使用正则表达式测试。 To fix the logic problem, one should consider changing && to ||要解决逻辑问题,应该考虑将&&更改为|| , ie , IE

while [ "$num" == "" ] || [ "$num" != $re ]

The second issue, is we are testing for negative matches to regular expression, pattern.第二个问题是我们正在测试与正则表达式模式的否定匹配。 So, this is done in two parts, one we need to use [[ "$num" =~ $re ]] for regular expression testing.所以,这分两部分完成,一个我们需要使用[[ "$num" =~ $re ]]进行正则表达式测试。 Then, we need to look for negative matches, ie append a !然后,我们需要寻找否定匹配,即附加一个! which yields:产生:

while [ "$num" == "" ] || ! [[ "$num" =~ $re ]

Having got this far, many people observed that there is actually no need to test for the empty string.说到这里,很多人观察到实际上没有必要测试空字符串。 That edge condition is already covered by the regular expression itself, so, we optimize out the redundant test.该边缘条件已经被正则表达式本身覆盖,因此,我们优化了冗余测试。 The answer now reduces to:答案现在简化为:

while ! [[ "$num" =~ $re ]

In addition to the above observation, here are my notes about regular expression ( some of the observation has been collated from other answers ):除了上面的观察,这里是我关于正则表达式的笔记(一些观察是从其他答案中整理出来的):

  • regular expressions can be tested with the [[ "$str" =~ regex ]] syntax可以使用[[ "$str" =~ regex ]]语法测试[[ "$str" =~ regex ]]
  • regular expressions match with $? == 0正则表达式与$? == 0 $? == 0 ( 0 == no error ) $? == 0 ( 0 == 没有错误)
  • regular expressions do not match with $? == 1正则表达式与$? == 1不匹配$? == 1 ( 1 == error ) $? == 1 ( 1 == 错误 )
  • regular expressions do not seem to work when quoted.正则表达式在引用时似乎不起作用。 recommend using [0-9] not "[0-9]"建议使用[0-9]而不是"[0-9]"

To implement a number validation, the following pattern seems to work:要实现数字验证,以下模式似乎有效:

str=""
while ! [[ "${str?}" =~ ^[0-9]+$ ]]
do
  read -p "enter a number: " str
done

You can mix regular expression filters with regular arithmetic filters for some really nice validation results:您可以将正则表达式过滤器与常规算术过滤器混合使用,以获得一些非常好的验证结果:

str=""
while ! [[ "${str?}" =~ ^[0-9]+$ ]] \
    || (( str < 1 || str > 15 ))
do
  read -p "enter a number between 1 and 15: " str
done

NB I used the ${str?} syntax ( instead of $str ) for variable expansion as it demonstrates good practice for catching typos.注意,我使用${str?}语法(而不是$str )进行变量扩展,因为它展示了捕获拼写错误的良好做法。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM