Correspondência de padrões em várias linhas

5

O que é uma maneira rápida e fácil de validar se o padrão "301 domaname.com 200" estiver presente no BASH quando distribuído em várias linhas de saída?

Eu estava usando algo como o seguinte:

 awk '/301|domain.com|200/'
 pcregrep -M '301|domain\.com|200'

mas a ordem não importa. Não tenho certeza de como declará-lo. O que eu pensei que iria funcionar, aparentemente, não está pegando os fins de linha.

pcregrep -M '301.*domain\.com.*200'

Histórico:

Estou criando um pequeno servidor mod_rewrite e preciso de uma maneira de monitorar quais domínios estão sendo redirecionados para quais destinos.

Como resultado, estou montando um pequeno script de verificação do Nagios que irá lidar com isso para mim.

O que eu tenho até agora é o seguinte:

curl qa-mod-rewrite.domain.com -i -I -L

HTTP/1.1 301 Moved Permanently
Via: 1.1 GREGORY
Connection: close
Proxy-Connection: close
Date: Thu, 14 Nov 2013 16:35:19 GMT
Location: http://qa.domain.com/
Content-Type: text/html; charset=iso-8859-1
Server: Apache/2.2.3 (CentOS)

HTTP/1.1 200 OK
Via: 1.1 GREGORY
Connection: Keep-Alive
Proxy-Connection: Keep-Alive
Content-Length: 56772
Expires: -1
Date: Thu, 14 Nov 2013 16:35:03 GMT
Content-Type: text/html; charset=utf-8
Server: Microsoft-IIS/7.5
Cache-Control: no-cache, no-store
Pragma: no-cache
X-AspNet-Version: 2.0.50727
Set-Cookie: cfcausa.qa#sc_wede=1; path=/
Set-Cookie: ASP.NET_SessionId=i4z1c4ahqoiw13552z413hbs; path=/; HttpOnly
X-Powered-By: ASP.NET
    
por Tim Brigham 14.11.2013 / 17:56

5 respostas

5

Há um escopo para falso positivo, pois 301.*domain\.com.*200 corresponderia por exemplo:

HTTP/1.1 404 Not found
Content-Length: 3010
X-Pingback: http://blah.domain.com/xmlrpc
Last-Modified: Thu, 14 Nov 2009 19:27:05 GMT

Você poderia ser um pouco mais aprofundado e escrevê-lo, por exemplo:

curl -sIL http://qa-mod-rewrite.domain.com |
  tr -d '\r' |
  awk -v RS= '
    NR == 1 && $2 == "301" && /\nLocation: [^\n]*domain\.com/ {redir=1}
    $2 == "200" {end=1}
    END {exit !(redir*end)}'

Com dados variáveis:

url=$1
EXPECTED_REDIRECTION=$2
EXPECTED_REDIRECTION_CODE=$3
EXPECTED_TERMINAL_CODE=$4
export EXPECTED_REDIRECTION EXPECTED_REDIRECTION_CODE EXPECTED_TERMINAL_CODE

curl -sIL "$url" |
  tr -d '\r' |
  awk -v RS= '
    BEGIN {
      re = ENVIRON["EXPECTED_REDIRECTION"]
      gsub(/[][^.$+?\()]/, "\&",re)
      re = "\nLocation: [^\n]*" re
    }
    NR == 1 && $2 == ENVIRON["EXPECTED_REDIRECTION_CODE"] && $0 ~ re {redir=1}
    $2 == $ENVIRON["EXPECTED_TERMINAL_CODE"] {end=1}
    END {exit !(redir*end)}'
    
por 14.11.2013 / 20:40
3

Você estava perto de pcregrep . Você precisa incluir explicitamente \n junto com . em seu padrão

pcregrep -M '301(.|\n)*domain\.com(.|\n)*200'
    
por 14.11.2013 / 18:06
1

Você também pode fazer isso diretamente no modo Perl e parágrafo (-000):

perl -000ne 'print if /301/' file

Isso fornece a saída esperada quando executado no arquivo exato que você postou, mas provavelmente precisará ser ajustado para sua entrada real.

    
por 14.11.2013 / 18:29
0

Similar ao modo slurp de perl sed pode ler todo o arquivo ou string no buffer de retenção ("espaço de espera") para que o conteúdo do arquivo ou string possa ser tratado como uma única linha em "espaço de padrão" "(consulte" sed e pesquisa e substituição de várias linhas " ).

str='
HTTP/1.1 301 Moved Permanently
Via: 1.1 GREGORY
Connection: close
Proxy-Connection: close
Date: Thu, 14 Nov 2013 16:35:19 GMT
Location: http://qa.domain.com/
Content-Type: text/html; charset=iso-8859-1
Server: Apache/2.2.3 (CentOS)

HTTP/1.1 200 OK
Via: 1.1 GREGORY
Connection: Keep-Alive
Proxy-Connection: Keep-Alive
Content-Length: 56772
Expires: -1
Date: Thu, 14 Nov 2013 16:35:03 GMT
Content-Type: text/html; charset=utf-8
Server: Microsoft-IIS/7.5
Cache-Control: no-cache, no-store
Pragma: no-cache
X-AspNet-Version: 2.0.50727
Set-Cookie: cfcausa.qa#sc_wede=1; path=/
Set-Cookie: ASP.NET_SessionId=i4z1c4ahqoiw13552z413hbs; path=/; HttpOnly
X-Powered-By: ASP.NET
'

# GNU sed
# using [^\n] (to match any character except the newline character \n)
# cf. http://austinmatzko.com/2008/04/26/sed-multi-line-search-and-replace/
echo "$str" | 
  tr -d '\r' |
  sed -n -e '
     # if the first line copy the pattern to the hold buffer
     1h
     # if not the first line then append the pattern to the hold buffer
     1!H
     # if the last line then ...
     $ {
        # copy from the hold to the pattern buffer
        g
        # do the search and print all matching lines if there are the specified three matches in the given order
        /^.*\n\(HTTP\/[^\n]* 301 [^\n]*\).*\(\nLocation:[^\n]*domain\.com[^\n]*\).*\(\nHTTP\/[^\n]* 200 [^\n]*\).*$/s///p;
     }'

# output:
# HTTP/1.1 301 Moved Permanently
# Location: http://qa.domain.com/
# HTTP/1.1 200 OK


# FreeBSD sed
# using [^[:cntrl:]] (to match any character except control characters, especially the newline character \n)
# cf. http://en.wikipedia.org/wiki/Regular_expression#Character_classes
echo "$str" | 
  tr -d '\r' |
  sed -n -e '1h;1!H;${;g; /^.*\n\(HTTP\/[^[:cntrl:]]* 301 [^[:cntrl:]]*\).*\(\nLocation:[^[:cntrl:]]*domain\.com[^[:cntrl:]]*\).*\(\nHTTP\/[^[:cntrl:]]* 200 [^[:cntrl:]]*\).*$/s///p; }'


# output:
# HTTP/1.1 301 Moved Permanently
# Location: http://qa.domain.com/
# HTTP/1.1 200 OK
    
por 26.11.2013 / 15:12
0

Obrigado a todos que responderam. Outra alternativa que eu estava trabalhando era a seguinte.

TMPFILE=$(mktemp)
curl $1 -i -I -L -s > $TMPFILE
cat $TMPFILE
echo ===================
pcregrep -M "1.1 301 Moved(.|\n)*Location: http(|s)://$2(.|\n)*1.1 200 OK" $TMPFILE > /dev/null 2>&1
STATUS=$?
echo $STATUS
rm $TMPFILE
exit $STATUS
    
por 26.11.2013 / 16:08

Tags