여러 줄의 로그 파일이 있는데 이를 한 줄의 로그로 변환하고 싶습니다.
여러 줄의 예:
6/13/2015 12:00:47 AM - { 562} START Web
6/13/2015 12:00:47 AM - Requested Web connection from 123.125.71.103 [123.125.71.103], ID=562
6/13/2015 12:01:24 AM - { 563} START POP3
6/13/2015 12:01:24 AM - Requested POP3 connection from 10.127.251.37 [10.127.251.37], ID=563
6/13/2015 12:01:24 AM - ( 563) USER [email protected]
6/13/2015 12:01:24 AM - POP3 connection with 10.127.251.37 [10.127.251.37] ended. ID=563
6/13/2015 12:01:24 AM - { 563} END POP3
6/13/2015 12:01:24 AM - { 564} START POP3
6/13/2015 12:01:24 AM - Requested POP3 connection from 10.127.251.37 [10.127.251.37], ID=564
6/13/2015 12:01:24 AM - ( 564) USER [email protected]
6/13/2015 12:01:24 AM - POP3 connection with 10.127.251.37 [10.127.251.37] ended. ID=564
6/13/2015 12:01:24 AM - { 564} END POP3
6/13/2015 12:01:40 AM - Web connection with 123.125.71.103 [123.125.71.103] ended. ID=562
6/13/2015 12:01:40 AM - { 562} END Web
먼저, 동일한 로그 ID(예: "562")와 일치하는 이와 같은 단일 출력 라인을 원합니다.
6/13/2015 12:00:47 AM - { 562} START Web 6/13/2015 12:00:47 AM - Requested Web connection from 123.125.71.103 [123.125.71.103], ID=562 6/13/2015 12:01:40 AM - Web connection with 123.125.71.103 [123.125.71.103] ended. ID=562 6/13/2015 12:01:40 AM - { 562} END Web
6/13/2015 12:01:24 AM - { 563} START POP3 6/13/2015 12:01:24 AM - Requested POP3 connection from 10.127.251.37 [10.127.251.37], ID=563 6/13/2015 12:01:24 AM - ( 563) USER [email protected] 6/13/2015 12:01:24 AM - POP3 connection with 10.127.251.37 [10.127.251.37] ended. ID=563 6/13/2015 12:01:24 AM - { 563} END POP3
6/13/2015 12:01:24 AM - { 564} START POP3 6/13/2015 12:01:24 AM - Requested POP3 connection from 10.127.251.37 [10.127.251.37], ID=564 6/13/2015 12:01:24 AM - ( 564) USER [email protected] 6/13/2015 12:01:24 AM - POP3 connection with 10.127.251.37 [10.127.251.37] ended. ID=564 6/13/2015 12:01:24 AM - { 564} END POP3
다음 bash 스크립트를 완료했지만 모든 "POP3" 또는 "웹" 메시지를 메시지 ID를 기준으로 분리하는 대신 한 줄로 병합하기 때문에 예상대로 작동하지 않습니다.
스크립트:
#!/bin/bash
HOME=/var/tmp/test.txt
ID=`((awk '$6 ~/[0-9]\W/ {print $6}' $HOME | awk '{gsub (/)/, ""); print}' | awk '{gsub (/}/, ""); print}') && (awk '$11 ~/[0-9]/ {print $11}' $HOME | awk '{gsub ("ID=", ""); print}'))`
for ID in $HOME
do
awk '!/Web/' $HOME | xargs >> final.txt
awk '/Web/' $HOME | xargs >> final.txt
done
동일한 ID만 병합하는 루프를 만드는 방법에 대한 제안이 있습니까?
답변1
모든 것을 awk에서 할 수 있습니다. 읽기 ID는 아래에 결합되어 있습니다.
awk '{
line = $0;
# ID is { XXX } or ( XXX )
if ( /[{(] *[0-9]+[})]/ ) {
id = $0;
sub(/ *[})].*/,"", id);
sub(/.*[({] */,"", id);
}
# ID is ID=XXX
else if ( $NF ~ /ID=/ ) {
id = $NF;
sub(/[^=]*=/,"",id);
}
# else ID= previous value
# save line into a assoc. array of IDs
final[id] = final[id]""line" "; # add space between lines
}
END {
# print foreach id
for ( id in final ) {
print final[id];
}
}
' /var/tmp/text.txt
인쇄 ID와 같은 중복 정보를 줄이고 다음과 같은 접두사만 사용할 수 있습니다.
# remove ID
sub(/ID=[0-9]/,"",id);
sub(/[({] *[0-9]+[})]/,"",id);
END {
# print foreach id
for ( id in final ) {
#Print ID then the rest of the line
printf("[ID=%d]: %s\n", id, final[id]);
}
}
답변2
@mikeserv의 접근 방식을 기반으로 다음과 같은 결과를 얻습니다.
스크립트:
( sed -e'y/)},={/(((((/' \
-e's/-\([^(I]*\)[^0-9]*\([0-9]*\)[( ]*/- \2 -\1/;=' |
paste -d- - - |
sort -t- -nk3,3 -nk1,1 |
sed -e's/^[^-]*-//;:n' -e'h;$!N' \
-e's/\(-\([^-]*-\).*[^ ]\) *\n\([^-]*-\)\{2\}\2/\1 - \3/;tn' \
-ex\;:t -e's/\(\([^-]*-\)[^/]*\) - *\2/\1,/;tt' -e'p;g;D'
) < in.txt > out.txt
6/13/2015 12:00:47 AM - 562 - START Web, Requested Web connection from 123.125.71.103 [123.125.71.103] - 6/13/2015 12:01:40 AM - Web connection with 123.125.71.103 [123.125.71.103] ended., END Web
6/13/2015 12:01:24 AM - 563 - START POP3, Requested POP3 connection from 10.127.251.37 [10.127.251.37], +OK ArGoSoft Mail Server Pro for WinNT/2000/XP( Version 1.8 (1.8.9.6( - 6/13/2015 12:01:24 AM - CAPA, -ERR Unknown command, USER [email protected], +OK Password required for [email protected], PASS XXXXXXXXX, +OK Mailbox locked and ready, Adding address to POP Before SMTP manager, STAT, +OK 178 97537344, UIDL, +OK, ., LIST, +OK, ., QUIT, +OK Aba he, POP3 connection with 10.127.251.37 [10.127.251.37] ended., END POP3
6/13/2015 12:04:25 AM - 564 - START POP3, Requested POP3 connection from 10.127.251.37 [10.127.251.37], +OK ArGoSoft Mail Server Pro for WinNT/2000/XP( Version 1.8 (1.8.9.6( - 6/13/2015 12:04:25 AM - CAPA, -ERR Unknown command, USER [email protected], +OK Password required for [email protected], PASS XXXXXXXXX, +OK Mailbox locked and ready, Adding address to POP Before SMTP manager, STAT, +OK 178 97537344, UIDL, +OK, ., LIST, +OK, . - 6/13/2015 12:04:26 AM - QUIT, +OK Aba he, POP3 connection with 10.127.251.37 [10.127.251.37] ended., END POP3
6/13/2015 12:04:36 AM - 565 - START Web, Requested Web connection from 31.133.9.16 [31.133.9.16], Web connection with 31.133.9.16 [31.133.9.16] ended., END Web
6/13/2015 12:07:26 AM - 566 - START POP3, Requested POP3 connection from 10.127.251.37 [10.127.251.37], +OK ArGoSoft Mail Server Pro for WinNT/2000/XP( Version 1.8 (1.8.9.6( - 6/13/2015 12:04:25 AM - CAPA, -ERR Unknown command, USER [email protected], +OK Password required for [email protected], PASS XXXXXXXXX, +OK Mailbox locked and ready, Adding address to POP Before SMTP manager, STAT, +OK 178 97537344, UIDL, +OK, ., LIST, +OK, . - 6/13/2015 12:04:26 AM - QUIT, +OK Aba he, POP3 connection with 10.127.251.37 [10.127.251.37] ended., END POP3
이 예의 4번째 줄에서 "31.133.9.16 [31.133.9.16]에 대한 웹 연결이 종료되었습니다." 이전의 타임스탬프가 누락된 것을 볼 수 있습니다. 이는 "웹 연결..."으로 시작하는 모든 유사한 로그에 대해 동일한 문제입니다. POP3 메시지가 포함된 다른 모든 로그의 경우 모든 것이 정상입니다.
첫 번째 메시지뿐만 아니라 나머지 모든 "웹 연결..." 메시지의 타임스탬프를 포함하도록 sed 명령을 어떻게 수정해야 합니까?
답변3
타임스탬프에만 의존하는 경우 다음이면 충분합니다.
sed -e:n -e'$!N;s/^\(\([^-]*-\).*\)\n *\2/\1:::/;tn' -eP\;D <in >out
N
현재 줄에 재귀적으로 ext 줄을 추가하고, 현재 줄의 시작 부분에 있는 모든 문자(첫 번째 -
대시 포함)가 추가된 줄의 시작 부분과 일치할 수 있는 경우 추가 타임스탬프를 제거하고 두 문자를 연결합니다. s///
교체가 t
성공 하면 다른 줄의 레이블 sed
로 다시 분기됩니다 . 그렇지 않으면 보류 중인 모든 병합 데이터가 제거되기 전에 표준 출력으로 인쇄되고 위에서 부터 재시도가 시작됩니다.:n
N
P
D
sed
샘플 데이터를 기반으로 다음이 인쇄됩니다.
6/13/2015 12:00:47 AM - { 562} START Web ::: Requested Web connection from 123.125.71.103 [123.125.71.103], ID=562
6/13/2015 12:01:24 AM - { 563} START POP3 ::: Requested POP3 connection from 10.127.251.37 [10.127.251.37], ID=563 ::: ( 563) USER [email protected] ::: POP3 connection with 10.127.251.37 [10.127.251.37] ended. ID=563 ::: { 563} END POP3::: { 564} START POP3 ::: Requested POP3 connection from 10.127.251.37 [10.127.251.37], ID=564 ::: ( 564) USER [email protected] ::: POP3 connection with 10.127.251.37 [10.127.251.37] ended. ID=564 ::: { 564} END POP3
6/13/2015 12:01:40 AM - Web connection with 123.125.71.103 [123.125.71.103] ended. ID=562 ::: { 562} END Web
그러나 이것은 분명히 좋지 않습니다. 병합하려는 것 같습니다.ID- 미안합니다. 다음은 작동합니다. 또한 입력에 나타나는 중복된 타임스탬프와 IDS도 지웁니다.
sed -e'y/)},={/(((((/' \
-e's/-\([^(I]*\)[^0-9]*\([0-9]*\)[( ]*/- \2 -\1/;=' |
paste -d- - - |
sort -t- -nk3,3 -nk1,1 |
sed -e's/^[^-]*-//;:n' -e'h;$!N' \
-e's/\(-\([^-]*-\).*[^ ]\) *\n\([^-]*-\)\{2\}\2/\1 - \3/;tn' \
-ex\;:t -e's/\(\([^-]*-\)[^/]*\)- *\2/\1:::/;tt' -e'p;g;D'
6/13/2015 12:00:47 AM - 562 - START Web ::: Requested Web connection from 123.125.71.103 [123.125.71.103] - 6/13/2015 12:01:40 AM - Web connection with 123.125.71.103 [123.125.71.103] ended. ::: END Web
6/13/2015 12:01:24 AM - 563 - START POP3 ::: Requested POP3 connection from 10.127.251.37 [10.127.251.37] ::: USER [email protected] ::: POP3 connection with 10.127.251.37 [10.127.251.37] ended. ::: END POP3
6/13/2015 12:01:24 AM - 564 - START POP3 ::: Requested POP3 connection from 10.127.251.37 [10.127.251.37] ::: USER [email protected] ::: POP3 connection with 10.127.251.37 [10.127.251.37] ended. ::: END POP3
답변4
따라서 각 행의 ID는 6번째 필드 또는 이전 필드에 있으므로 아무것도 하지 않고도 ID별로 모든 행을 수집할 수 있습니다.sub
awk -F"[ }=)]+" '
NF{
if($6 ~ "[0-9]{3}")
ids=$6
else
ids=$(NF-1)
if(!M[ids])
M[ids]=$0
else
M[ids]=M[ids] " " $0
}
END{
for(i in M)
print M[i]
}' /var/tmp/text.txt