awk를 사용하여 패턴 쌍 찾기 및 라인 연결

awk를 사용하여 패턴 쌍 찾기 및 라인 연결

일부 프로세스의 로그가 포함된 대용량 파일이 있습니다. 로그에는 "REQUEST(항상)/RESPONSE(때때로)"와 같은 줄이 포함되어 있지만 RESPONSE가 반드시 REQUEST 다음 줄인 것은 아닙니다. RESPONSE가 나타나기 전에 REQUEST 헤더가 여러 번 나타날 수 있습니다. 존재하는 경우 요청과 응답에 참여하고 해당 행을 인쇄하고 싶습니다. 이것이 지금까지 시도한 것이지만 출력에 일부 줄이 누락되었습니다.

awk 'BEGIN {filename = "log1.etb"}
    {line_num++; print "FNR: " FNR " NR: " NR " Counter: " line_num;
    if ($0 ~ /REQUEST.*RPCLIB/)
                        {seqid = $0; sub(/^.*@SeqID/,"SeqID",seqid);
                        line_req = $0; line_resp = ""; ref_resp = 0;
                        ref_req = line_num; tot_req++;
                        print "REQUEST: " $0;
                        for(i=1;i<=line_num+99999;i++1) {getline < "log.etb"; if ($0 ~ /RESPONSE/ && $0 ~ seqid) {ref_resp = +i; line_resp = $0; break;}};
                        print "FNR: " FNR " NR: " NR " REQUEST: " ref_req " RESPONSE: " ref_resp " " seqid;
                        print line_req"+"line_resp > filename;
                        FNR = line_num-1; NR = FNR;
                        }
    }
    END {print "Total REQUEST: " tot_req}
    ' ../EXX/log.etb

입력하다:

REQUEST  2019-01-16 00:32:07.809@{fields}@SeqID     = 9517
RESPONSE 2019-01-16 00:32:07.809@{fields}@SeqID     = 9517 , Partner SeqID = 3393
REQUEST  2019-01-16 00:32:07.809@{fields}@SeqID     = 9515
REQUEST  2019-01-16 00:32:07.810@{fields}@SeqID     = 9520
RESPONSE 2019-01-16 00:32:07.810@{fields}@SeqID     = 9520 , Partner SeqID = 3395

원하는 출력:

REQUEST  2019-01-16 00:32:07.809@{fields}@SeqID     = 9517+W02/RESPONSE 2019-01-16 00:32:07.809@{fields}@SeqID     = 9517 , Partner SeqID = 3393
REQUEST  2019-01-16 00:32:07.809@{fields}@SeqID     = 9515+
REQUEST  2019-01-16 00:32:07.810@{fields}@SeqID     = 9520+W02/RESPONSE 2019-01-16 00:32:07.810@{fields}@SeqID     = 9520 , Partner SeqID = 3395

요청/응답에 연결된 SeqID 번호이지만 어느 시점에서 로그에 다시 나타날 수 있습니다. 또한 REQUEST는 RESPONSE 이전에 여러 번 발생할 수 있으며 RESPONSE는 발생할 수도 있고 발생하지 않을 수도 있습니다.

답변1

댓글을 달 수가 없어서 답변으로 댓글을 남깁니다. 죄송합니다.
SEQID가 일치하면 REQUEST와 RESPONSE에 참여하고 싶습니까? 먼저 seqid를 기준으로 데이터를 정렬하면 어떨까요? 응답이 항상 요청을 따르도록 보장합니다.

답변2

나는 당신을 도울 수 없지만 awk그렇게 하기 위해 이 Bash 스크립트를 만들었습니다.

최소한 Bash v4가 필요합니다., 하지만 이는 매우 일반적이어야 합니다..

stdin의 입력이 필요합니다. 즉, 다음과 같이 호출해야 합니다.

cat logfile | script.sh

또는:

script.sh < logfile

나는 그것이 바람직할 것이라고 생각하여 의도적으로 이렇게 했지만 파일 이름을 스크립트에 포함시키는 것은 쉽습니다. 그냥 명령 cat -n 의 |.

다음을 처리합니다.

  • 답장 없음
  • 해당 ID를 사용하여 찾은 최신 요청에 응답을 추가하여 요청을 반복합니다.
  • @ 기호 다음에 SeqID 필드를 허용합니다(첫 번째 명령 sed의 정규식을 살펴보세요.)
  • REQUEST 및 RESPONSE 리터럴 정규식을 레코드 구별 기준으로 사용합니다(if-elif-else-fi코드 블록 보기)
  • 일치하는 req/resp 쌍 연결+

화타이

#!/bin/bash

declare -A reqs=()

{
while IFS= read -r line ; do
    read -r seqid rest <<<"${line}"
    line="${line#${seqid} }"
    if [[ "${line}" =~ REQUEST ]] ; then
        [ "${reqs[$seqid]}" ] && printf '%s+\n' "${reqs[$seqid]}"
        reqs[$seqid]="${line}"
    elif [[ "${line}" =~ RESPONSE ]] && [ "${reqs[$seqid]}" ] ; then
        printf '%s+%s\n' "${reqs[$seqid]}" "${line}"
        unset reqs[$seqid]
    else
        printf 'strange record at line no. %s\n' "${line}" >&2
    fi
done < <(cat -n | sed -e 's/\(.*@\)SeqID *= *\([0-9]\+\)\(.*\)/\2 &/') ;
printf '%s+\n' "${reqs[@]}" ;
} | sort -k 1 | sed -e 's/\(^\|+\)[[:blank:]]\+[0-9]\+[[:blank:]]\+/\1/g'

답변3

다음을 시도했는데 훌륭하게 작동합니다.

for i in `cat k.txt| awk  -F "=" '{print $2}'| awk -F "," '{print $1}'| sed -r "s/\s+//g"| sort| uniq`; do sed -n '/'$i'/p' k.txt|sed '1s/$/\+/g'| sed "N;s/\n/W02\//g";done

산출

for i in `cat k.txt| awk  -F "=" '{print $2}'| awk -F "," '{print $1}'| sed -r "s/\s+//g"| sort| uniq`; do sed -n '/'$i'/p' k.txt|sed '1s/$/\+/g'| sed "N;s/\n/W02\//g";done

REQUEST  2019-01-16 00:32:07.809@{fields}@SeqID     = 9515+
REQUEST  2019-01-16 00:32:07.809@{fields}@SeqID     = 9517+W02/RESPONSE 2019-01-16 00:32:07.809@{fields}@SeqID     = 9517 , Partner SeqID = 3393
REQUEST  2019-01-16 00:32:07.810@{fields}@SeqID     = 9520+W02/RESPONSE 2019-01-16 00:32:07.810@{fields}@SeqID     = 9520 , Partner SeqID = 3395
praveen@praveen:~$ 

답변4

다음 코드를 시도했지만 대용량 파일에서는 시간이 너무 오래 걸립니다.

awk '{
    if ($0 ~ /REQUEST/ && $0 ~ /RPCLIB/)
        {seqid = $0; sub(/^.*@SeqID/,"SeqID",seqid);
        line_req = $0; line_resp = "";
        rng_s = NR; rng_e = NR + 99999;
        cmd = "awk '\''/RESPONSE.*" seqid "/ && NR >= " rng_s " && NR <= " rng_e " {print $0;exit}'\'' logfile"
        cmd | getline line_resp;
        close(cmd);
        print line_req"+"line_resp;
        }
    }
    ' logfile

관련 정보