我可以将正则表达式的求值存储到变量中吗?

时间:2019-03-20 13:39:01

标签: regex bash

我收到的字符串可以全为破折号,在这种情况下,对我来说是可接受的(例如123423-56788-456522-34245),或者不是全数字且仍用破折号分隔,在这种情况下,我不接受(例如123423-56788-shelve-34245)。

为了确定字符串是否可接受,我构建了以下if块:

REGEX_FOR_ONLY_NUMERICAL_CHANGELISTS='^[0-9-]+$'
if [[ ${BUILD_ID} =~ ${REGEX_FOR_ONLY_NUMERICAL_CHANGELISTS} ]]
then
    echo true
else
    echo false
fi 

以上if块工作正常。但是,如果我要编程为另一种语言(例如Java),则将评估直接分配给变量。例如:

int a = 3; 
int b = 5; 
boolean test = (a < b);

上面的test将是true:我将评估表达式(a < b)并将其结果存储到一行中的变量test中。

我想知道是否有可能在Bash中做同样的事情。环顾网络,我没有发现很多例子。多亏this answer,我才意识到,如果我这样做:

bash$ false_expression=$((2 == 4))
bash$ true_expression=$((2 == 2))

...这两个变量分别采用值01。它不完全是truefalse,但我仍然可以接受。 但是,我似乎无法对我的表情做同样的事情,因为如果这样做的话:

InvalidCL=123423-56788-shelve-34245
MyRegex='^[0-9-]+$'
FalseExpression=$((${InvalidCL} =~ ${MyRegex}))

...第三次分配引发此错误:

-bash: 123423-56788-shelve-34245 =~ ^[0-9-]+$: attempted assignment to non-variable (error token is "=~ ^[0-9-]+$")

我不是真正的bash专家,所以我的问题(希望它不是很傻)是:是否可以将评估分配给变量?我可以看到我的{{1 }}被评估为if [[ myExpression ]],所以我不明白为什么我无法将此评估分配给变量。有人可以解释吗?

4 个答案:

答案 0 :(得分:3)

如果您真的想一次完成任务,那么可以这样做:

FalseExpression=$( [[ "$InvalidCL" =~ $MyRegex ]] && echo 1 || echo 0)

其中1代表true0代表false。但是请记住,这不是传统的Bash方法。 Bash中0的结果表示没有错误,即,如果表达式的计算结果为true,则退出状态为:

$ echo $?
0

请注意,使用单个(代表命令替换,而示例中的((则评估数学表达式。

传统上,人们可能会这样做:

$ [[ "$InvalidCL" =~ $MyRegex ]]
$ FalseExpression=$?

Bash将最后一次操作的退出状态存储在“ $?”中,其行为与$(())运算符相反。如果表达式为true,则$?将存储0,而$ {{}}将返回1。如果您来自C背景,可能对后者更熟悉。我建议不要混合使用这些方法。如果一个结果可能具有不同的含义,则调试脚本可能会非常困难。

答案 1 :(得分:1)

您也可以这样做:

[[ ${BUILD_ID} =~ ${REGEX_FOR_ONLY_NUMERICAL_CHANGELISTS} ]]
val=$?

避免调用子shell。同样,成功时val为0,失败时为1。

答案 2 :(得分:1)

如果您希望将单行直接分配给数字布尔值,则可以在测试中使用“非”运算符。

  

强烈 建议您为此添加一些解释性评论。

# assign an integer BOOLEAN value from the test for a match
# the ! means NOT, inverts a 0/1 OS exit code from [[ ]]
match="$( [[ ! "$string" =~ $pattern ]]; echo $?; )"  
# now $match is 1 (TRUE) if it *matched* the pattern

为更清楚起见,请创建一个带有注释的函数来封装逻辑,然后从一行开始调用那个

boolMatch() { 
   local match str="$1" pat="$2"

   # test the match
   [[ "$str" =~ $pat ]]

   # invert the return to a boolean value
   match=$(( ! $? ))

   # pass back the boolean
   echo $match
}

$: boolMatch foo bar
0
$: boolMatch foo foo
1
$: match=$( boolMatch $stringToCheck $patternToUse )

答案 3 :(得分:1)

其他人已经指出了如何解决获取正则表达式匹配的 boolean返回值的问题。

关于实际问题的措词,我想指出的是,一个regex表达式的求值结果实际上自动存储在bash的环境变量中。 $BASH_REMATCH数组将整个匹配项存储在索引0处,并将捕获组存储在它们各自的索引处。参见:https://www.linuxjournal.com/content/bash-regular-expressions

$?中的手动分配相比,该数组中的元素数量也可能更舒适,可以用作匹配成功的指标。如果${#BASH_REMATCH[*]}为零,则最后一个正则表达式不匹配。

您得到的错误消息是因为正则表达式匹配语法仅在[[ ... ]]构造中定义,而不是在$(( ... ))算术评估中定义,因此当它看到=时会认为您认为必须尝试某种分配。