AWK: como comparar duas variáveis com expressão regular

3

Eu tenho uma linha com valores separados por dois pontos que eu quero processar no awk. As linhas são tratadas de forma diferente se a variável $4 contiver varible $3 no início.

Então eu escrevi a expressão: $4 ~ /^$3/ , mas unfortunaltely isso não funciona, nunca corresponde. O que há de errado, como posso usar uma variável em um padrão de expressão regular?

Este é o exemplo completo:

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

O resultado é sempre BAD , por ex. aqui, linha:

bind_bind.1:urknall:Running:Running 18 hours ago:

deve imprimir GOOD , mas imprime:

BAD bind_bind.1: Running ≠ Running 18 hours ago
    
por Marc Wäckerlin 02.02.2018 / 11:54

2 respostas

8

/^$3/ é uma expressão regular que garante que nunca coincide corresponde a registros que possuem 3 após o final do registro (o operador% âncora regular corresponde ao final do assunto, para não ser confundido com o $ $ operador que é usado para excluir os campos por número).

Para testar se o terceiro campo ocorre no início do quarto campo, pode-se fazer uma correspondência de expressão regular com awk , que retornará a posição inicial da correspondência (ou -1 se nenhuma correspondência for encontrada) :

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

ou, para uma comparação de strings,

awk -F ':' 'substr($4, 1, length($3)) == $3 { ..."GOOD"... ; next } { ..."BAD"... }'
    
por 02.02.2018 / 12:01
7

Você pode colocar a regex no lado direito de um ~ em uma string, não precisa ser uma construção /.../ . (A diferença pode ter sido relacionada à análise do RE em tempo de execução ou em tempo de compilação, mas não tenho certeza.) E lembre-se que em awk , o cifrão não significa expansão variável como em shell ou Perl, então você precisa concatenar $3 com o resto da string:

O primeiro corresponde, o segundo não:

$ echo 'foo fo+' |awk '$1 ~ "^" $2'
foo fo+
$ echo 'foo o+' |awk '$1 ~ "^" $2'
$

/^$2/ é considerado como um regex com um literal $2 , e o $ é a âncora de fim de linha. Como você não pode ter nada após o EOL, o RE nunca pode corresponder.

    
por 02.02.2018 / 12:21