2016-12-05 16 views
0

私は壊れたログを変換するための助けが必要です。私は管理者から受け取ります(残念ながら、それを修正するつもりはありません)。 基本的に、ログに重複した最初の列が含まれている場合があります。別の列の値がnullの場合は削除したい場合があります。重複した行を削除する

これは、あなたが見ることができるように、それはかなり

datetime,auth_protocol,result,client,port,login 
2016-07-15 09:34:52,www,PASS,111.222.333.444,5593,[email protected] 
2016-07-15 09:34:52,www,PASS,111.222.333.444,NULL,[email protected] 
2016-08-14 00:51:35,www,PASS,NULL,19509,[email protected] 
2016-08-14 00:51:35,www,PASS,444.333.222.111,19509,[email protected] 
2016-09-16 05:08:46,www,FAIL,123.456.789.222,45673,[email protected] 
2016-09-16 15:35:55,www,FAIL,123.456.789.222,NULL,[email protected] 
2016-09-17 17:10:01,www,FAIL,111.222.333.444,55516,[email protected] 

をどのように見えるかで、いくつかの行は、最初の列(日付)を重複しています。

1:私は何をしようとしている

は、にあるすべての列については、その最初の列は4または5列(IPまたはポート)

2を比較し、重複している:重複行を削除します。列4または5

これは正しい出力することsouldにNULL値を持つ:

datetime,auth_protocol,result,client,port,login 
2016-07-15 09:34:52,www,PASS,111.222.333.444,5593,[email protected] 
2016-08-14 00:51:35,www,PASS,444.333.222.111,19509,[email protected] 
2016-09-16 05:08:46,www,FAIL,123.456.789.222,45673,[email protected] 
2016-09-16 15:35:55,www,FAIL,123.456.789.222,NULL,[email protected] 
2016-09-17 17:10:01,www,FAIL,111.222.333.444,55516,[email protected] 

私はそれを明確に聞こえる願っていますし、d

+2

あなたが試したことにいくつかのコードを示すことができます。 – Inian

+0

複製された行は常にログ内で直接続けられますか?列4または5にNULLが含まれていて、複製された行ではないケースはありますか?私は正しい例 – jas

+0

1)はい、いつも 2)はい、NULL値が存在することができ、私はいくつかの醜いアドホックをしたが、その醜い;) 猫account.csv | grep -Ff <(cat account.csv | cut -d '、' -f1 | sort | uniq -d)| grep -v "、NULL、" >> temp.csv; 読み取り中。 do single = $(echo $ line | cut -d "、" -f1); if [[$(cat temp.csv | grep "$ single")== ""]]; echo $ line >> temp.csv; fi done Wyjun

答えて

2

ログファイル上で2回の反復を行うことによって、あなたは最初の反復内のすべての使用の日付を収集することができます。そして、日付がすでに2回目の反復で使用されている場合はNULLログを削除:

$ awk -F, '$4$5 !~ /NULL/ {d[$1]=1} 
      NR == FNR { next } 
      !d[$1] || $4$5 !~ /NULL/' input.log input.log 

最初の反復dは、指定したフィールドでNULLが含まれていない行から使用される日付が移入されます。

NR == FNRは、最初の反復ファイルに対してのみtrueです。

2番目の反復行には、列4または5にNULLが含まれていない場合に印刷されます。または、dに使用日が含まれていない場合は、

+0

うわー、完璧に動作します!ありがとう、本当に感謝します! – Wyjun

+0

eyyy、あなたは私の$ 4 $ 5をコピーしています! – 123

+0

@ 123私は、OPにはIPとPortが含まれているとOPが言っているので、安全である理由はないことに気付きました。 – andlrc

3

このawkを使用できます。

ファイルを2回反復処理します。
初回カウントダウン
二重引用符ではない行または二番目にNULLを含まない行を出力します。

awk -F, 'NR==FNR{a[$1]++;next}a[$1]<2||$4$5!~/NULL/' file{,} 

datetime,auth_protocol,result,client,port,login 
2016-07-15 09:34:52,www,PASS,111.222.333.444,5593,[email protected] 
2016-08-14 00:51:35,www,PASS,444.333.222.111,19509,[email protected] 
2016-09-16 05:08:46,www,FAIL,123.456.789.222,45673,[email protected] 
2016-09-16 15:35:55,www,FAIL,123.456.789.222,NULL,[email protected] 
2016-09-17 17:10:01,www,FAIL,111.222.333.444,55516,[email protected] 
+0

同じ日付を共有する2つのNULL行があり、有効なレコードが関連付けられていない場合、これは失敗します。しかし、必ずしも心配する必要はありません。 – andlrc

+0

@andlrc質問のためだけに書いています。 – 123

1

bashの短いスクリプトソリューションを使用して、1回のパスで配列を使用できます。 (ファイルの長さにもよりますが、awkの方がダブルパスが早いかもしれませんが、ファイルが大きい場合はこのバージョンが有利かもしれません)。このスクリプトはすべての行を読み込むだけですが、次の行が読み取られるまで各行の出力を延期し、日付/時刻の比較を行って重複エントリが存在するかどうかを判断します。日付が等しい場合は、IPフィールドをチェックします。 IPがNULLの場合、その行の印刷はスキップされます。

これは多くのアプローチのほんの一例です。あなたのデータとそれを試してみる:

編集テストがidフィールド

#!/bin/bash 

fn="${1:-/dev/stdin}" ## read file or stdin 

prevln="" ## previous line & prev and curr arrays of values 
declare -a prev=(' ' ' ' ' ' ' ' ' ' ' ' ' ') 
declare -a curr 
declare -i iddup=0 ## flag marking duplicate in 'id' field 

IFS=$' ,\t\n' ## add ',' to internal field separator 

while read -r line || test -n "$line"; do ## read each line 
    curr=($(echo $line)) ## fill current array with values 
    ## test prev date/time with curr date/time 
    if [ "${prev[0]}" = "${curr[0]}" -a "${prev[1]}" = "${curr[1]}" ]; then 
     if [ "${prev[4]}" != "NULL" ]; then  ## if prev IP != NULL print 
      echo "$prevln"      ## otherwise, skip print 
     fi 
     [ "${curr[5]}" = "NULL" ] && iddup=1 || iddup=0 ## flag id dup 
    elif [ "$iddup" -eq '0' ]; then ## if date/time inequal, print line 
     [ -n "$prevln" ] && echo "$prevln" 
    fi 
    prevln="$line"  ## assign line to prevln 
    prev=(${curr[@]}) ## assign curr to prev array 
done <"$fn" 

## same test for the last line after loop exits 
curr=($(echo $line)) 
if [ "${prev[0]}" = "${curr[0]}" -a "${prev[1]}" = "${curr[1]}" ]; then 
    if [ "${prev[4]}" = "NULL" ]; then 
     echo "$line" 
    elif [ "${curr[4]}" = "NULL" ]; then 
     echo "$prevln" 
    else 
     echo "$prevln" 
    fi 
else ## if date/time inequal, print line 
    [ -n "$prevln" ] && echo "$prevln" 
fi 

入力ファイル

$ cat dat/log.txt 
2016-07-15 09:34:52,www,PASS,111.222.333.444,5593,[email protected] 
2016-07-15 09:34:52,www,PASS,111.222.333.444,NULL,[email protected] 
2016-08-14 00:51:35,www,PASS,NULL,19509,[email protected] 
2016-08-14 00:51:35,www,PASS,444.333.222.111,19509,[email protected] 
2016-09-16 05:08:46,www,FAIL,123.456.789.222,45673,[email protected] 
2016-09-16 15:35:55,www,FAIL,123.456.789.222,NULL,[email protected] 
2016-09-17 17:10:01,www,FAIL,111.222.333.444,55516,[email protected] 

使用例/出力にNULLために追加

$ bash logdups.sh <dat/log.txt 
2016-07-15 09:34:52,www,PASS,111.222.333.444,5593,[email protected] 
2016-07-15 00:51:35,www,PASS,444.333.222.111,19509,[email protected] 
2016-09-16 05:08:46,www,FAIL,123.456.789.222,45673,[email protected] 
2016-09-16 15:35:55,www,FAIL,123.456.789.222,NULL,[email protected] 
2016-09-17 17:10:01,www,FAIL,111.222.333.444,55516,[email protected] 
+0

うまく動きませんでした。最初の2行が複製されます:) – Wyjun

+0

Hmm。同じデータを使用していますか?あなたのテストデータに問題はありませんでした。私はダブルチェックします。あなたの見出しを追加しても、テストデータでうまくいきました。複製されている最初の2行を投稿して、それを並べ替えます。 (IPフィールドの後ろにあるIDの 'NULL'も考慮して重複を示していますか?)それは、あなたのデータをもう一度見て、私がそのチェックを追加して保持しています) –

+0

@Wyjun OK私は 'id'フィールドに' NULL'のテストを追加しましたが、これは重複した状態であるとは考えていませんでした。 –