
私は次の形式のログファイルを扱っています:
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