我有一行用冒号分隔的值,我想在 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
结果总是BAD
,例如这里,行:
bind_bind.1:urknall:Running:Running 18 hours ago:
应该打印GOOD
,但打印:
BAD bind_bind.1: Running ≠ Running 18 hours ago
答案1
您可以将正则表达式放在字符串中 a 的右侧~
,它不必是一个/.../
构造。 (差异可能与在运行时或编译时解析 RE 有关,但我不确定。)请记住,在 中awk
,美元符号并不意味着像 shell 或 Perl 中那样的变量扩展,因此您需要连接$3
到字符串的其余部分:
第一个匹配,第二个不匹配:
$ echo 'foo fo+' |awk '$1 ~ "^" $2'
foo fo+
$ echo 'foo o+' |awk '$1 ~ "^" $2'
$
/^$2/
被视为$2
其中包含文字的正则表达式,并且$
是行尾锚点。由于 EOL 之后您将无法拥有任何内容,因此 RE 永远无法匹配。
答案2
/^$3/
是一个正则表达式保证永远不会匹配因为它匹配3
记录末尾之后的记录($
正则表达式锚运算符匹配主题末尾,不要与$
awk
用于按数字取消引用字段的运算符混淆)。
要测试第三个字段是否出现在第四个字段的开头,可以使用 进行正则表达式匹配match()
,这将返回匹配的起始位置(如果未找到匹配,则返回 -1):
awk -F ':' 'match($4, $3) == 1 { ..."GOOD"... ; next } { ..."BAD"... }'
或者,对于字符串比较,
awk -F ':' 'substr($4, 1, length($3)) == $3 { ..."GOOD"... ; next } { ..."BAD"... }'