使用@s在grep中出现错误行为

时间:2018-05-25 12:48:50

标签: bash grep undefined-behavior

我正在为nullmailer编写一个小包装器,当我注意到,imho是grep中的一个不需要的行为。 特别是我注意到了@s的一些奇怪。

它会破坏包含@的字符串,并会产生错误的输出。

TL; DR

电子邮件地址有一些规则要遵循(E.G. RFC 2822),所以我会为它们使用故意错误的正则表达式,只是为了让事情变得更短。 请注意,这不会改变我要求的问题。

我在这篇文章中使用的是电子邮件地址,但问题显然是每个字符串中至少有一个@。

我写了一个小脚本来帮助我解释我发现的":

#!/bin/bash

funct1() {

  arr=(local1@domain.tld local2@domain.tld)
  regex="[[:alnum:]]*@[[:alpha:]]*\.[[:alpha:]]\{2,\}"
  for dest in ${arr[@]}; do
    printf "%s\n" "$dest" | grep -o -e "$regex"
  done
}
funct2() {
  arr=(local1@domain.tld local2@domain.tld)
  regex="[[:alpha:]]*@[[:alpha:]]*\.[[:alpha:]]\{2,\}"
  for dest in ${arr[@]}; do
    printf "%s\n" "$dest" | grep -o -e "$regex"
  done
}

funct3(){
  arr=(local1@dom1@ain.tld local2@dom2@ain.tld)
  regex="[[:alpha:]]*@[[:alpha:]]*@[[:alpha:]]*\.[[:alpha:]]\{2,\}"
  for dest in ${arr[@]}; do
    printf "%s\n" "$dest" | grep -o -e "$regex"
  done
}

funct4(){
  arr=(local1@dom1@ain.tld local2@dom2@ain.tld)
  regex="[[:alpha:]]*@[[:alnum:]]*@[[:alpha:]]*\.[[:alpha:]]\{2,\}"
  for dest in ${arr[@]}; do
    printf "%s\n" "$dest" | grep -o -e "$regex"
  done
}

printf "One @, all parts of regex right:\n"
funct1
printf "One @, first part of regex wrong:\n"
funct2
printf "Two @, first and second part of regex wrong:\n"
funct3
printf "Two @, first part of regex wrong:\n"
funct4
exit 0

为了更好地理解这个问题,我使用了两种类型的字符串:local1@domain.tldlocal1@dom1@ain.tld,在我看来,grep的行为方式不正确,字符串至少包含@。 / p>

输出结果为:

One @, all parts of regex right:
local1@domain.tld
local2@domain.tld

One @, first part of regex wrong:
@domain.tld
@domain.tld

Two @, first and second part of regex wrong:

Two @, first part of regex wrong:
@dom1@ain.tld
@dom2@ain.tld

funct1有一个正则表达式可以解决整个字符串,所以没问题,所有字符串都会被打印出来。

funct2有一个正则表达式,只解决从@到结尾的字符串,所以我应该期待的是没有输出,因为表达式错误;相反,我所拥有的是字符串的第二部分...

这就是为什么我决定在字符串中添加第二个@并进行一些测试。

funct3只解决从第二个@到最后的字符串,所以我应该期待的是没有输出,因为正则表达式中的错误;好的,没有输出。

funct4有一个正则表达式,只解决从第一个@到最后的字符串,所以我在这里应该期待的是他不能给我任何东西;相反,我所拥有的是第一个@的输出,就像funct2一样。

除了funct1我根本不应该有任何输出,我是对的吗?

为什么grep会在第一个@?

中破坏结果

我认为这是一种不受欢迎的行为,因为这样结果将包含在完全不符合我表达式的字符串中。

我错过了什么吗?

编辑:删除标记undefined-behavior

1 个答案:

答案 0 :(得分:1)

你的正则表达式有问题,按设计工作。您也可以将@的数量计算为测试。我个人会创建一个这样的布尔方法:

#!/bin/bash

# -- is email address valid ? --    
function isEmailValid() {
      echo "$1" | egrep -q "^([A-Za-z]+[A-Za-z0-9]*((\.|\-|\_)?[A-Za-z]+[A-Za-z0-9]*){1,})@(([A-Za-z]+[A-Za-z0-9]*)+((\.|\-|\_)?([A-Za-z]+[A-Za-z0-9]*)+){1,})+\.([A-Za-z]{2,})+"
}


if isEmailValid "_#@us@.com" ;then
        echo "VALID "
else
        echo "INVALID"
fi


if isEmailValid "us@ibm.com" ;then
        echo "VALID "
else
        echo "INVALID"
fi

或更简单:

function isEmailValid() {
      regex="^([A-Za-z]+[A-Za-z0-9]*((\.|\-|\_)?[A-Za-z]+[A-Za-z0-9]*){1,})@(([A-Za-z]+[A-Za-z0-9]*)+((\.|\-|\_)?([A-Za-z]+[A-Za-z0-9]*)+){1,})+\.([A-Za-z]{2,})+"
      [[ "${1}" =~ $regex ]]
}