tail 및 grep을 사용하여 관심 있는 행을 필터링하여 정기적으로 실시간으로 추적하는 로그 파일이 있습니다. 하지만 이러한 행에는 항상 관심이 없는 데이터가 많이 포함되어 있지만 행에서 내가 원하는 부분만 볼 수 있도록 구문 분석하기가 어렵습니다. 각 행 항목의 형식은 주로 목록 레이블과 따옴표(때때로 공백 포함)로 묶인 데이터입니다. 다음은 (삭제된) 로그 줄의 예입니다.
2017:11:29-11:29:56 filter-1 httpproxy[3194]: id="0001" severity="info" sys="SecureWeb" sub="http" name="http access" action="pass" method="CONNECT" srcip="10.11.12.13" dstip="14.3.1.4" user="" group="" ad_domain="" statuscode="200" cached="0" profile="REF_HttPro1234 (Campus2)" filteraction="REF_HttStu (Allow Policy)" size="6518" request="0x915a3e00" url="https://website.net/" referer="" error="" authtime="0" dnstime="1" cattime="73" avscantime="0" fullreqtime="61576999" device="0" auth="6" ua="" exceptions="" category="9998" reputation="unverified" categoryname="Uncategorized" country="United States" application="krux" app-id="826"
2017:11:29-11:29:56 filter-1 httpproxy[3194]: id="0001" severity="info" sys="SecureWeb" sub="http" name="http access" action="pass" method="GET" srcip="10.13.14.15" dstip="154.6.75.10" user="" group="" ad_domain="" statuscode="200" cached="0" profile="REF_HttPro1235 (Campus1)" filteraction="REF_HttStu (Allow Policy)" size="3161" request="0x6b4d5610" url="http://host.com/mini_banner.png" referer="http://www.web.com/computers.htm" error="" authtime="0" dnstime="0" cattime="64" avscantime="848" fullreqtime="50046" device="0" auth="6" ua="Mozilla/5.0 (X11; CrOS x86_64 9765.85.0) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/61.0.3163.123 Safari/537.36" exceptions="" category="111" reputation="trusted" categoryname="Education/Reference" sandbox="-" content-type="image/png"
한 가지 주목할 점은 모든 레이블이 모든 행에 표시되는 것은 아니라는 것입니다. 예를 들어, application 및 app-id는 첫 번째 줄에 표시되지만 두 번째 줄에는 표시되지 않습니다.
위 줄을 입력 예시로 사용하여 출력으로 원하는 예시는 srcip, Categoryname 및 url 태그만 순서대로 표시하는 것입니다. 원하는 출력은 다음과 같습니다.
10.11.12.13 Uncategorized https://website.net/
10.13.14.15 Education/Reference http://host.com/mini_banner.png
나는 표시된 라벨을 즉시 조정할 수 있도록 조정하기 쉬운 솔루션을 찾고 있습니다.
답변1
귀하의 데이터는 고도로 구조화되어 있습니다.키="값", 따라서 gnu awk를 사용하여 키 이름 목록을 인수로 사용하고 해당 값만 인쇄하는 작은 쉘 스크립트를 작성할 수 있습니다. 예를 들어 myscript
:
#!/bin/bash
awk -v lhs="$*" '
BEGIN{ FPAT = "[a-z-]*=\"[^\"]*\""
nwant = split(lhs,want)
}
{ for(i=1;i<=NF;i++){
start = match($i,/([a-z-]*)="([^"]*)"/,a)
key[a[1]] = a[2]
}
for(i=1;i<=nwant;i++){printf "%s ",key[want[i]]; key[want[i]] = ""}
printf "\n"
}'
이렇게 myscript srcip categoryname url
하면 awk 변수가 처음에 배열로 분할되는 lhs
단일 문자열로 설정됩니다. want
행은 awk에 의해 패턴과 일치하는 필드로 나뉩니다.키="값"내장 FPAT
변수를 사용합니다.
각 줄에서 각 필드에 대해 2개의 캡처 그룹으로 분할합니다 match()
. 하나는 키용이고 다른 하나는 큰따옴표 안의 부분용입니다. 이는 awk에 의해 배열에 저장되고 키 문자열로 색인된 연관 배열 a
에 저장됩니다 .key
그런 다음 원하는 각 키에 대해 값을 인쇄하고 해당 행에 해당 키가 없으면 다음 행의 값을 지웁니다. 분명히 이는 모든 데이터가 필요한 구조를 가지고 있다고 가정하고, 알파벳이 아닌 문자가 있는 값이나 키 내에서 (")를 처리하도록 변경해야 합니다.
4.0 이전의 GNU awk(gawk) 버전에는 FPAT
패턴과 일치하는 필드로 행을 분할하는 기능이 내장되어 있지 않으므로 이 작업을 직접 수행해야 했습니다.
#!/bin/bash
awk -v lhs="$*" '
BEGIN{ nwant = split(lhs,want) }
{ input = $0
while(match(input,"[a-z-]*=\"[^\"]*\"")>0){
field = substr(input,RSTART,RLENGTH)
input = substr(input,RSTART+RLENGTH)
start = match(field,/([a-z-]*)="([^"]*)"/,a)
key[a[1]] = a[2]
}
for(i=1;i<=nwant;i++){printf "%s ",key[want[i]]; key[want[i]] = ""}
printf "\n"
}'
분명히 두 개의 일치 호출을 하나로 결합할 수 있지만 이는 원래 일치와의 차이점을 보여줍니다.
답변2
사용(POSIX 규격) sed
...
sed 's/.* srcip="\([^"]*\)" .* url="\([^"]*\)" .* categoryname="\([^"]*\)" .*/\1 \3 \2/' logfile
여기에는 멋진 내용이 없습니다. 키를 찾아 값을 괄호로 묶어 \(..\)
역참조로 사용할 수 있습니다. 그런 다음 문자열을 요구 사항에 따라 정렬된 공백으로 구분된 역참조로 바꿉니다 \1 \3 \2
.
산출:
10.11.12.13 Uncategorized https://website.net/
10.13.14.15 Education/Reference http://host.com/mini_banner.png
로그에 이러한 키가 모두 포함되지 않은 문자열이 포함되어 있으면 다음을 사용할 수 있습니다.
sed -n 's/.* srcip="\([^"]*\)" .* url="\([^"]*\)" .* categoryname="\([^"]*\)" .*/\1 \3 \2/p' logfile
그러면 패턴과 일치하는 줄만 인쇄됩니다.
물론 스트리밍에 사용하려면 파일 이름을 제거하고 다음을 수행하십시오.[something sending logs to stdout] | sed ...