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

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/28126274/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-09-18 12:14:49  来源:igfitidea点击:

shell script in bash using regex in while loop

regexbashubuntu

提问by Tommy Yap

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

回答by Marc Bredt

regualar expression can be used with the operator =~not ~=like you used it.

regualar表达可以与运营商使用=~~=喜欢你使用它。

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)). The return value is 0 if the string matches the pattern, and 1 otherwise. 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. 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. Substrings matched by parenthesized subexpressions within the regular expression are saved in the array variable BASH_REMATCH. The element of BASH_REMATCH with index 0 is the portion of the string matching the entire regular expression. The element of BASH_REMATCH with index n is the portion of the string matching the nth parenthesized subexpression.

可以使用额外的二元运算符 =~,其优先级与 == 和 != 相同。使用时,右边的字符串
运算符被视为扩展的正则表达式并相应地匹配(如在 regex(3) 中)。如果字符串与模式匹配,则返回值为 0,否则为 1。如果正则表达式在语法上不正确,则条件表达式的返回值为 2。如果启用了 shell 选项 nocasematch,则执行匹配时不考虑字母字符的大小写。可以引用模式的任何部分以强制引用部分作为字符串进行匹配。必须谨慎对待正则表达式中的括号表达式,因为正常的引用字符在括号之间会失去意义。如果模式存储在 shell 变量中,引用变量扩展会强制将整个模式作为字符串进行匹配。正则表达式中括号内子表达式匹配的子字符串保存在数组变量 BASH_REMATCH 中。索引为 0 的 BASH_REMATCH 元素是匹配整个正则表达式的字符串部分。索引为 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. During the first run ${num}is not set so it will not fit at least one number, ${num}then evaluates to an empty string. Afterwards it just contains the input entered.

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

回答by tripleee

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

回答by Stephen Quan

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. i.e. 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 ||, i.e.

这里的问题是&&这几乎意味着左表达式的那一刻false,整个表达式是false. 即当有人输入非空响应时,它会中断循环并且从不使用正则表达式测试。要解决逻辑问题,应该考虑更改&&||,即

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. Then, we need to look for negative matches, i.e. append a !which yields:

第二个问题是,我们正在测试与正则表达式模式的否定匹配。所以,这分两部分完成,一个我们需要[[ "$num" =~ $re ]]用于正则表达式测试。然后,我们需要寻找否定匹配,即附加 a!产生:

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
  • regular expressions match with $? == 0( 0 == no error )
  • regular expressions do not match with $? == 1( 1 == error )
  • regular expressions do not seem to work when quoted. recommend using [0-9]not "[0-9]"
  • 可以使用[[ "$str" =~ regex ]]语法测试正则表达式
  • 正则表达式与$? == 0( 0 == 无错误 )匹配
  • 正则表达式与$? == 1( 1 == error )不匹配
  • 正则表达式在引用时似乎不起作用。建议[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

N.B. I used the ${str?}syntax ( instead of $str) for variable expansion as it demonstrates good practice for catching typos.

注意,我使用${str?}语法(而不是$str)进行变量扩展,因为它展示了捕获拼写错误的良好做法。