用 Perl 或 Python 重写日志解析脚本(摆脱 awk)

Twi*_*ell 0 awk python perl python3

我需要完成过滤日志文件中机器人活动的任务。

解决方案应仅显示满足以下条件的记录

  • 用户登录、用户更改密码、用户在同一秒内注销。
  • 这些操作(登录、更改密码、注销)相继发生,中间没有其他条目。

输入数据示例

[a lot of data]
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 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| -
[a lot of data]
Run Code Online (Sandbox Code Playgroud)

我编写了下面的代码以完成任务

awk 'BEGIN { FS=" " } { c[$5]++; l[$5,c[$5]]=$0 } END { for (i in c) { if (c[i] == 3) for (j = 1 ; j <= c[i]; j++) print l[i,j] } }' $1
Run Code Online (Sandbox Code Playgroud)

用法:

./parse_log.sh 日志文件.log

输出:

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: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: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| -
Run Code Online (Sandbox Code Playgroud)

但我想知道用 Perl 或 Python 编写的替代方案(外部库的使用最少)会是什么样子?

Ed *_*ton 9

这不是一个答案,但它对于注释来说太大并且需要格式化,因此为了解决您的评论“Python 代码更容易阅读和理解它的作用。”,仅供参考,一个具有合理变量名称的 AWK 脚本我认为 你的Python脚本所做的事情看起来很像你的Python脚本,但更简短,因为为了操作文本,awk已经为你做了所有你必须在Python中编写代码才能完成的常见事情:

awk -v column=5 '
    { records[$column] = records[$column] $0 ORS }
    END {
        for ( timestamp in records ) {
            if ( gsub(ORS,"&",records[timestamp]) > 2 ) {
                printf "%s", records[timestamp]
            }
        }
    }
' logfile.log
Run Code Online (Sandbox Code Playgroud)

但是在处理之前将整个文件读入内存是解决此问题的一种非常低效的方法。您应该在每次时间变化时进行测试并打印:

awk -v column=5 '
    $column != prev {
        prt()
        records = ""
        prev = $column
    }
    { records = records $0 ORS }
    END { prt() }

    function prt() {
        if ( gsub(ORS,"&",records) > 2 ) {
            printf "%s", records
        }
    }
' logfile.log
Run Code Online (Sandbox Code Playgroud)


Twi*_*ell 5

解决方案本身是用Python\xc2\xa03编写的。

\n
#!/usr/bin/env python3\n\nimport sys\nimport re\nfrom collections import defaultdict\n\n\ncolumn_delimiter = sys.argv[1]\ncolumn = int(sys.argv[2]) - 1\n\nrecords = defaultdict(list)\n\nwith open(sys.argv[3]) as inputfile:\n  for lines in inputfile:\n    line = lines.rstrip('\\n')\n    row_record = line.split(column_delimiter)\n    records[row_record[column]].append(line)\n\nfor timestamps in records.values():\n    if len(timestamps) == 3:\n        for i in range(len(timestamps)):\n          if (re.search('logged in|changed password|logged off', timestamps[i])):\n                  print(timestamps[i])\n
Run Code Online (Sandbox Code Playgroud)\n

用法:parse_log.py ' ' 5 logfile.log

\n

Python 代码更容易阅读和理解它的作用。

\n

  • `Python 代码更容易阅读和理解它的作用。` 很大程度上是一个观点问题(我个人无法说出 python 脚本在做什么,而我确实知道你的 awk 脚本做了什么)但是 awk 脚本你的问题写得不好,有多余的代码,塞满了一行,并使用了一堆神秘的单字母变量名,所以很容易使用任何工具(包括 awk)编写更容易阅读和理解的东西。 (10认同)
  • 您的时间戳被离散化为整秒。无论你承认与否,你*有*这个问题! (4认同)
  • 所以:这是当之无愧的赞成票。请注意,我对上一个问题的“挑剔”观点的信号处理观点仍然成立:12:00:00 之后 900 毫秒发生的事情以及 12:00:01 之后 100 毫秒发生的事情只有 200 毫秒(不到一秒)分开,但获得两个不同的时间戳,“12:00:00”和“12:00:01”。如果您有截断或舍入的时间值,则无法确定以时间量化分辨率检测事件!你需要计算同一秒或下一秒发生的所有事情, (2认同)