awkを使用して同じファイルの行パターンを比較する方法

awkを使用して同じファイルの行パターンを比較する方法

まず、私は今学び始めて、awkこれを完了するために挑戦したいbashので、完全な答えを見つけるのではなく、解決策ではなく、あちこちでいくつかのヒントとこれを行う方法を探しています。

デフォルトでは、このような大きなログファイルを取得し、次のように構成する必要があります。

  • ユーザーがログインし、パスワードを変更し、ユーザーは同じ秒以内にログアウトします(3つのタスクはすべて1秒以内に完了する必要があります)。
  • これらのタスク(ログイン、パスワードの変更、ログアウト)は、その間に他のタスクなしで順番に発生します。

したがって、私の出力は、上記のテストと一致するユーザーのプロファイル名のみを表示する必要があります。

fxsciaqulmlk
erdsfsdfsdf
fxsciaqulmla

ここにログファイルの一部があります。

Mon, 22 Aug 2016 13:15:39 +0200|178.57.66.225|fxsciaqulmlk| - |user logged in| -
Mon, 22 Aug 2016 13:15:39 +0200|178.57.66.225|fxsciaqulmlk| - |user changed password| -
Mon, 22 Aug 2016 13:15:39 +0200|178.57.66.225|fxsciaqulmlk| - |user logged off| -
Mon, 22 Aug 2016 13:15:42 +0200|178.57.66.225|faaaaaa11111| - |user logged in| -
Mon, 22 Aug 2016 13:15:40 +0200|178.57.66.215|terdsfsdfsdf| - |user logged in| -
Mon, 22 Aug 2016 13:15:49 +0200|178.57.66.215|terdsfsdfsdf| - |user changed password| -
Mon, 22 Aug 2016 13:15:49 +0200|178.57.66.215|terdsfsdfsdf| - |user logged off| -
Mon, 22 Aug 2016 13:15:59 +0200|178.57.66.205|erdsfsdfsdf| - |user logged in| -
Mon, 22 Aug 2016 13:15:59 +0200|178.57.66.205|erdsfsdfsdf| - |user logged in| -
Mon, 22 Aug 2016 13:15:59 +0200|178.57.66.205|erdsfsdfsdf| - |user changed password| -
Mon, 22 Aug 2016 13:15:59 +0200|178.57.66.205|erdsfsdfsdf| - |user logged off| -
Mon, 22 Aug 2016 13:17:50 +0200|178.57.66.205|abcbbabab| - |user logged in| -
Mon, 22 Aug 2016 13:17:50 +0200|178.57.66.205|abcbbabab| - |user changed password| -
Mon, 22 Aug 2016 13:17:50 +0200|178.57.66.205|abcbbabab| - |user changed profile| -
Mon, 22 Aug 2016 13:17:50 +0200|178.57.66.205|abcbbabab| - |user logged off| -
Mon, 22 Aug 2016 13:19:19 +0200|178.56.66.225|fxsciaqulmla| - |user logged in| -
Mon, 22 Aug 2016 13:19:19 +0200|178.56.66.225|fxsciaqulmla| - |user changed password| -
Mon, 22 Aug 2016 13:19:19 +0200|178.56.66.225|fxsciaqulmla| - |user logged off| -
Mon, 22 Aug 2016 13:20:42 +0200|178.57.67.225|faaaa0a11111| - |user logged in| -

これが私が付いているところです。

#!/bin/bash

LIMIT="3"
LOG_FILE="${1}"


if [[ ! -e "${LOG_FILE}" ]]; then
  echo "Cannot open log file: ${LOG_FILE}" >&2
  exit 1
else
  grep 'changed password' -B1 -A1 ${LOG_FILE} \
  | awk '{print $5"\t"$6"\t"$9" "$10}' \
  | awk 'BEGIN{FS="|"; OFS="\t"} {print $1,$3,$4}' \
  | cut -d "    " -f1,3,4,5

....

fi

私のロジックは次のとおりです。 「ログイン」の後と「ログアウト」の前の行に「変更されたパスワード」文字列があることを確認したいと思います。これら2つの項目が一致したら、これらの操作が同じ秒以内に完了したかどうかを比較したいと思います。

私のロジックが良いかどうか、awkこれを行うには何を使うべきかを教えてください。私も学びたいのですが、何か説明していただければ本当にありがとうございます。

ベストアンサー1

ファイルに3行のウィンドウを保持し、最後のパターンが見つかるたびに現在と最後の2行をテストできます。

BEGIN {
    FS = "|"
    text[2] = "user logged in"
    text[1] = "user changed password"
    text[0] = "user logged off"
}
    
$5 == text[0] && action[1] == text[1] && action[2] == text[2] &&
$3 == user[1] && $1 == time[1] && $3 == user[2] && $1 == time[2] {
    print $3
}
    
{
    time[2] = time[1]; user[2] = user[1]; action[2] = action[1]
    time[1] = $1; user[1] = $3; action[1] = $5
}

使用法:

$ awk -f tst.awk file
fxsciaqulmlk
erdsfsdfsdf
fxsciaqulmla
  • このBEGINグループは、最初の行を解析する前に実行され、FSフィールド区切り文字です。

  • 2番目のグループは条件付きで印刷ユーザーと一致します。スパゲッティに似ていますが動作します。awk最初のエラーが見つかった場合は、各セクションの評価が停止されるため、順序が重要です。したがって、まずその行に「ログアウト」が含まれているかどうかをテストし、最初の2行に別のタスクが含まれているかどうかをテストします。

  • 最後のグループは3行のウィンドウを予約するために使用されます。ハッシュのある変数は[1]最後の行を意味し、ハッシュのある変数は[2]2番目から最後の行を意味します。

  • 注:初期化されていないすべての変数は、空の文字列(または数値0、型が緩い)として扱われます。また、awk配列は連想配列であり、1ここでは2ハッシュ値です。


最初の数行について、さらに異なるテストをしたい場合は、スケルトンは次のようになります。

condition_for_last_row {
    for (i=1;i<=2;i++) {
        n = split(prev[i],arr)
        # do comparisons here, arr[1] to arr[n] are
        # the fields of the i-th previous row
    }
}

{
    prev[2] = prev[1]
    prev[1] = $0
}

おすすめ記事