使用'=〜'运算符的Bash正则表达式匹配意外失败

时间:2017-01-26 13:23:38

标签: regex bash

这是一个由=~调用的旧bash正则表达式匹配的小单元脚本

#!/bin/bash

# From "man bash"
# An additional binary operator, =~, is available, with the same
# precedence 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.

# The above should say regex(7) of course

match() {
   local REGEX=$1
   local VAL=$2
   [[ $VAL =~ $REGEX  ]]
   RES=$?
   case $RES in
      0) echo "Match of '$VAL' against '$REGEX': MATCH" >&2 ;;
      1) echo "Match of '$VAL' against '$REGEX': NOMATCH" >&2 ;;
      2) echo "Error in regex expression '$REGEX'" >&2 ;;
      *) echo "Unknown returnvalue $RES" >&2 ;;
   esac
   echo $RES
}

v() {
   SHALL=$1
   IS=$2
   if [ "$SHALL" -eq "$IS" ]; then echo "OK"; else echo "NOT OK"; fi
}

unit_test() {
   v 0 "$(match A                A  )"
   v 0 "$(match A.               AB )"
   v 0 "$(match A[:digit:]?      A  )"
   v 0 "$(match A[:digit:]       A6 )"
   v 0 "$(match \"A[:digit:]*\"  A6 )"  # enclosing in quotes needed otherwise fileglob happens
   v 0 "$(match A[:digit:]+      A6 )"
   v 0 "$(match A                BA )"
   v 1 "$(match ^A               BA )"
   v 0 "$(match ^A               Ab )"
   v 0 "$(match 'A$'             BA )"
   v 1 "$(match 'A$'             Ab )"
}

unit_test

看起来很简单,但运行它会产生:

Match of 'A' against 'A': MATCH
OK
Match of 'AB' against 'A.': MATCH
OK
Match of 'A' against 'A[:digit:]?': MATCH
OK
Match of 'A6' against 'A[:digit:]': NOMATCH
NOT OK
Match of 'A6' against 'A[:digit:]*': MATCH
OK
Match of 'A6' against 'A[:digit:]+': NOMATCH
NOT OK
Match of 'BA' against 'A': MATCH
OK
Match of 'BA' against '^A': NOMATCH
OK
Match of 'Ab' against '^A': MATCH
OK
Match of 'BA' against 'A$': MATCH
OK
Match of 'Ab' against 'A$': NOMATCH
OK

人们会期待

Match of 'A6' against 'A[:digit:]'

Match of 'A6' against 'A[:digit:]+'

成功。

我做错了什么?

3 个答案:

答案 0 :(得分:2)

请务必将字符类括在括号[]中,以将其匹配为字符列表,即[[:digit:]]

string="A6"
[[ $string =~ A[[:digit:]] ]]
echo $?
0

Bracket-Expressions上查看更多内容。

答案 1 :(得分:2)

您在错误的上下文中使用[:digit:]。这些字符类应在括号表达式中使用,例如[[:digit:][:alnum:]._+-](例如)。

应该是:

if [[ "A6" =~ A[[:digit:]] ]] ; then
    echo "match"
fi

答案 2 :(得分:1)

正如评论中所建议的那样,ShellCheck工具会显示问题所在:

The output of ShellCheck