정규화된 필드/열에는 없지만 로그 파일에서 특정 문자열을 추출해야 합니다. 예를 들어:
date="2017-01-03 08:30:02 -0500",fac=f_kernel_ipfilter,area=a_general_area,type=t_attack,pri=p_major,hostname=hostname,category=policy_violation,event="ACL deny",attackip=1.1.1.1,attackzone=internal,app_risk=low,app_categories=remote-admin,netsessid=c550e586ba75a,src_geo=US,srcip=1.1.1.1,srcport=38256,srczone=internal,protocol=6,dst_geo=US,dstip=2.2.2.2,dstport=80,dstzone=external,rule_name=Deny_All,reason="Traffic denied by policy.",application=SSH
srcip, srczone, 프로토콜, dstip, dstzone, dstport 및 rule_name을 얻고 싶습니다. 나는 현재 필요하지 않은 OUT 필드를 제거하기 위해 Perl 게으른 매칭을 사용하고 있습니다. ,dstport=80,
로그 파일의 위치에 관계없이 이 8개의 문자열과 쉼표 내의 데이터만 가져오는 방법이 있습니까 ? 동일한 데이터에 대한 입력 위치가 다양하므로 이를 어렵게 만듭니다.
답변1
빠르고 더러운 방법은 다음과 같습니다 perl
.
$ perl -F, -lane '@l = grep {/srcip|srczone|protocol|dstip|dstzone|dstport|rule_name/} @F;
print join ",",@l' file
srcip=1.1.1.1,srczone=internal,protocol=6,dstip=2.2.2.2,dstport=80,dstzone=external,rule_name=Deny_All
이는 -a
Perl을 awk처럼 동작하게 만들고 주어진 문자를 기반으로 입력 라인을 분할하여 -F
배열의 요소로 저장합니다 @F
. 그런 다음 grep
배열을 만들고 배열의 대상 단어와 일치하는 요소를 유지하고 @l
마지막으로 @l
인쇄 연결에 쉼표를 사용합니다.
패턴 중 하나라도 하위 패턴이 될 수 있으면 이 작업은 실패합니다 ( foo=bar
및 가 있다고 가정).foobar=baz
더 긴 대상 패턴 목록의 경우(실제 스크립트를 작성하지 않으려는 경우) 이를 배열에 저장하고 연결하여 |
grep의 정규 표현식을 만들 수 있습니다. 각 패턴 주위에 추가 하여 \b
하위 패턴이 일치하지 않도록 할 수도 있습니다 . 불필요한 임시 배열도 제거하면 다음과 같은 결과를 얻습니다.
$ perl -F, -lane '
BEGIN{
$pat="\\b" . join "\\b|",qw(srcip= srczone= protocol= dstip= dstzone= dstport= rule_name=)
} print join ",",grep {/$pat/}@F' file
srcip=1.1.1.1,srczone=internal,protocol=6,dstip=2.2.2.2,dstport=80,dstzone=external,rule_name=Deny_All
우리 상주 전문가는 sed awk 또는 [. ..] ~에서주문
죄송합니다. 하지만 이것은 정말 터무니없는 일입니다. 각 도구에서 이 작업을 수행하는 한 가지(여러 가지) 방법은 다음과 같습니다.
Bourne 쉘(다시). 이것을 사용하지 마십시오. 나는 단지 그것이 가능하다는 것을 증명하기 위해 보여드리는 것뿐입니다.
$ pat=(srcip= srczone= protocol= dstip= dstzone= dstport= rule_name=); $ o=""; while IFS=, read -a fields; do for f in "${fields[@]}"; do for pat in "${pat[@]}"; do [[ $f =~ $pat ]] && o="$f,$o" done done done < file ; echo ${o%,}
앗
대상 패턴을 파일에 저장합니다.
$ cat patterns srcip srczone protocol dstip dstzone dstport rule_name
그 다음에:
$ awk -F, '(NR==FNR){ pat[$0]++; next; } { for(i=1;i<=NF;i++){ split($i,a,"="); if(a[1] in pat){ printf "%s=%s,",a[1],a[2] } } print "" }' patterns file | sed 's/,$//' srcip=1.1.1.1,srczone=internal,protocol=6,dstip=2.2.2.2,dstport=80,dstzone=external,rule_name=Deny_All
sed
(및 쉘)$ pat=(srcip= srczone= protocol= dstip= dstzone= dstport= rule_name=); $ for p in ${pat[@]}; do sed -E "s/.*($p[^,]*).*/\1/" file; done | sed ':a;N;$!ba;s/\n/,/g' srcip=1.1.1.1,srczone=internal,protocol=6,dstip=2.2.2.2,dstzone=external,dstport=80,rule_name=Deny_All
Bourne 쉘(또는 모든 POSIX 쉘) + sed(1. 하지 마세요. 가능하지만 바보입니다)
$ set srcip= srczone= protocol= dstip= dstzone= dstport= rule_name= $ for f in "$@"; do sed "s/.*\($f[^,]*\).*/\1/" file; done | sed ':a;N;$!ba;s/\n/,/g' srcip=1.1.1.1,srczone=internal,protocol=6,dstip=2.2.2.2,dstzone=external,dstport=80,rule_name=Deny_All
답변2
GNU 솔루션 awk
:
gawk -v OFS= -v FPAT=',(srcip|srczone|protocol|dstip|dstzone|dstport|rule_name)=[^,]*' -e 'NF > 0 { $1=$1; print }'
여기서는 GNU 특정 기능을 사용합니다 awk
. 변수에 대해 정규식을 사용 하여 FPAT
필드의 형식을 지정하여 정규식과 일치하는 줄의 모든 부분이 에 할당 되도록 합니다 $1...$n
.$1
$1
$0
$1...$n
답변3
이에 대해 조금 늦었지만 제안을 제공하겠습니다. 이러한 종류의 데이터는 map
해싱에 적합합니다.
#!/usr/bin/env perl
use strict;
use warnings;
#for debugging - can be removed;
use Data::Dumper;
my @fields = qw ( srcip srczone protocol dstip dstzone dstport rule_name );
#read STDIN or files specified on command line (just like grep/sed/awk)
while ( <> ) {
#split commas
#then read key-value pairs.
my %row = map { m/(.*)=(.*)/ } split /,/;
#for debugging:
print Dumper \%row;
#print fields tab-separated and in order as above.
print join "\t", @row{@fields};
}
oneliner-ify는 철자를 입력해야 하는 필드 목록이 있기 때문에 약간 더 어렵습니다. 하지만:
perl -lane -F, 'BEGIN { @k = qw ( srcip srczone protocol dstip dstzone dstport rule_name ) } %r = map { m/(.*)=(.*)/ } @F; print join "\t", @r{@k}'
답변4
세게 때리다
IFS=, read -r -a fields <<< "$date"
results=()
for keyval in "${fields[@]}"; do
IFS='=' read -r key value <<< "$keyval"
case $key in
srcip|srczone|protocol|dstip|dstzone|dstport|rule_name) results+=("$keyval")
esac
done
(IFS=,; echo "${results[*]}")
srcip=1.1.1.1,srczone=internal,protocol=6,dstip=2.2.2.2,dstport=80,dstzone=external,rule_name=Deny_All