AWK:如何用正则表达式比较两个变量

Mar*_*lin 4 awk regular-expression

我有一行用冒号分隔的值,我想在 awk 中处理。如果$4变量$3在开头包含变量,则行的处理方式不同。

所以我写了表达式: $4 ~ /^$3/,但不幸的是这不起作用,它永远不会匹配。怎么了,如何在正则表达式模式中使用变量?

这是完整的示例:

green="$(tput setaf 2)"
red="$(tput setaf 1)"
yellow="$(tput setaf 3)"
normal="$(tput sgr0)"

stacks=$(docker stack ls --format='{{.Name}}')

for stack in ${stacks}; do
    status=$(docker stack ps --filter="desired-state=running" --format="{{.Name}}:{{.Node}}:{{.DesiredState}}:{{.CurrentState}}:{{.Error}}" ${stack})
    if test -z "$status"; then
        echo "${red}$stack$: disabled${normal}"
    else
        awk -F: '                                                                            
            $4 ~ /^$3/ {print "GOOD '"${green}"'" $1 ": " $4 "'"${normal}"'"}                
            $4 !~ /^$3/ {print "BAD '"${yellow}"'" $1 ": " $3 " ? " $4 $5 "'"${normal}"'"}   
        ' <<<${status}
    fi
done
Run Code Online (Sandbox Code Playgroud)

结果总是BAD,例如这里,行:

bind_bind.1:urknall:Running:Running 18 hours ago:
Run Code Online (Sandbox Code Playgroud)

应该打印GOOD,但打印:

BAD bind_bind.1: Running ? Running 18 hours ago
Run Code Online (Sandbox Code Playgroud)

ilk*_*chu 9

您可以将正则表达式放在~字符串中 a的右侧,它不必是一个/.../构造。(差异可能与在运行时或编译时解析 RE 有关,但我不确定。)请记住,在 中awk,美元符号并不意味着像 shell 或 Perl 中那样的变量扩展,因此您需要连接$3到字符串的其余部分:

第一个匹配,第二个不匹配:

$ echo 'foo fo+' |awk '$1 ~ "^" $2'
foo fo+
$ echo 'foo o+' |awk '$1 ~ "^" $2'
$
Run Code Online (Sandbox Code Playgroud)

/^$2/被视为带有文字的正则表达式$2,并且$是行尾锚点。由于在 EOL 之后您不能拥有任何东西,因此 RE 永远无法匹配。

  • @Kusalananda,`$2` ERE [是一个有效的 POSIX ERE,保证永远不会匹配](http://pubs.opengroup.org/onlinepubs/9699919799/basedefs/V1_chap09.html#tag_09_04_09)。 (4认同)
  • @OlivierDulac,这看起来像是 BRE 和 ERE 之间的另一个细微差别。在“9.3.8 BRE 表达式锚定”中,它说 _“&lt;dollar-sign&gt; 应该是一个锚,**当用作整个 BRE 的最后一个字符**时。”_,而在“9.4.9 ERE 表达式锚定”中" 它说 _"括号表达式外的 &lt;dollar-sign&gt; 应将它结束的表达式或子表达式锚定到字符串的末尾;"_(无论 `$` 出现在哪里) (2认同)

Kus*_*nda 8

/^$3/保证永远不会匹配的正则表达式,因为它匹配记录3末尾之后的记录($正则表达式运算符匹配主题末尾,不要与$ awk用于取消引用字段的运算符混淆按编号)。

要测试第三个字段是否出现在第四个字段的开头,可以使用正则表达式匹配match(),这将返回匹配的开始位置(如果未找到匹配,则返回 -1):

awk -F ':' 'match($4, $3) == 1 { ..."GOOD"... ; next } { ..."BAD"... }'
Run Code Online (Sandbox Code Playgroud)

或者,对于字符串比较,

awk -F ':' 'substr($4, 1, length($3)) == $3 { ..."GOOD"... ; next } { ..."BAD"... }'
Run Code Online (Sandbox Code Playgroud)