日付/時刻に基づいてログファイルの最後に表示される一意の行のみを印刷します。

日付/時刻に基づいてログファイルの最後に表示される一意の行のみを印刷します。

私は次の形式のログファイルを扱っています:

Oct 12 01:28:26 server program: 192.168.1.105 text for 1.105 
Oct 12 01:30:00 server program: 192.168.1.104 text for 1.104 
Oct 12 01:30:23 server program: 192.168.1.103 text for 1.103
Oct 12 01:32:39 server program: 192.168.1.101 text for 1.101 
Oct 12 02:28:26 server program: 192.168.1.105 text for 1.105 
Oct 12 02:30:00 server program: 192.168.1.104 text for 1.104
Oct 12 02:30:23 server program: 192.168.1.103 text for 1.103 
Oct 12 02:32:39 server program: 192.168.1.101 text for 1.101 

これを達成する必要があります:

Oct 12 02:28:26 server program: 192.168.1.105 text for 1.105 
Oct 12 02:30:00 server program: 192.168.1.104 text for 1.104
Oct 12 02:30:23 server program: 192.168.1.103 text for 1.103
Oct 12 02:32:39 server program: 192.168.1.101 text for 1.101

新しい出力をファイルに送信するにはどうすればいいでしょうか? 私はこれを試しました:

awk '!_[$6]++ {a=$6} END{print a}' logfile

しかし、期待した結果が得られません。awk または sed を使用して、文字列が最後に一致した時刻または日付/時刻に基づいて一意の行のみを取得するにはどうすればよいでしょうか。

答え1

2 回目のパスを実行する場合 (これは必ず実行する必要があります)、完全なレコードではなく行番号のみを保存することもできます。これにより、ロジックが簡単になります。

awk 'NR == FNR {if (z[$6]) y[z[$6]]; z[$6] = FNR; next} !(FNR in y)' logfile logfile

正しさの証明:

各行の処理の最後に、これまで処理されたすべての行番号がどちらかの値zまたは内のインデックス(値ではない)でyあり、両方ではありません。

の値によって表される行はz、各反復の終了時に、各 IP アドレスについてこれまでに確認された最新のレコードのみになります。

したがって、のインデックスはy、私たちが望む正確な線です。ない印刷する。

答え2

行全体を保存し($6配列インデックスとして使用)、END配列の要素を反復処理します。

awk '{z[$6]=$0};END{for (i in z) print z[i]}' logfile

ただし、結果はソートされません...次のようにすることができます:

awk '{z[$6]=NR" "$0};END{for (i in z) print z[i]}' logfile | sort -k1,1n | cut -f2-
### this space ^ is a literal TAB

行番号と行の内容が保存され、行番号で並べ替えることができます。


他の方法では、2 回目のパスで日付順に並べ替えますが (これはログなので)、入力に重複する行 (つまり行全体) が含まれている場合は重複したエントリが出力されます - 例grep:

awk '{z[$6]=$0};END{for (var in z) print z[var]}' logfile | grep -Fxf- logfile

または、以下のいずれかのみawk:

awk 'NR==FNR{z[$6]=$0;next}
FNR==1{for (var in z) y[z[var]]}
$0 in y' logfile logfile

答え3

同じ日の行のみがある場合は、次のように処理できます。

sort -k6 -k3r logfile | uniq -f3 | sort -k3

1 日以上にわたる行がある場合でも、この基本的なアプローチを使用できますが、並べ替えはより複雑にする必要があります。上記のコマンドは、タイムスタンプの時間部分 (例02:28:26) をタイムスタンプ全体のプロキシとして使用するため、1 日分のレコードしか処理できません。

答え4

ファイルを行ごとに反転することでロジックがシンプルになる

$ tac logfile | awk '!seen[$6]++' | tac
Oct 12 02:28:26 server program: 192.168.1.105 text for 1.105 
Oct 12 02:30:00 server program: 192.168.1.104 text for 1.104
Oct 12 02:30:23 server program: 192.168.1.103 text for 1.103 
Oct 12 02:32:39 server program: 192.168.1.101 text for 1.101 

関連情報