ログファイルから複数のカンマ区切り文字列を抽出する方法は?

ログファイルから複数のカンマ区切り文字列を抽出する方法は?

完全修飾フィールド/列にはありませんが、ログファイルから特定の文字列を抽出する必要があります。たとえば、

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

これは-aPerlを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または[。 ..] ~から注文

申し訳ありません。しかし、これは本当にとんでもないことです。各ツールでこれを行う1つの方法は次のとおりです。

  1. 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%,}
    
  2. アッ

    ターゲットパターンをファイルに保存します。

    $ 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
    
  3. 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
    
  4. 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

関連情報