用于从日志文件生成报告的 awk

awk for generating Report from logfile

我有一个包含如下字符串的日志:

1001031075825052016
1001041080225052016
1001030125825052016
1001031140325052016
1001040180025052016
1001030180125052016
1001031075926052016
1001041080226052016
1001030125926052016
1001031140126052016
1001030180026052016
1001030180026052016

其中:
前6个字符是id,第7个字符如果有人进入则等于1,如果有人离开则为0,从第8到11个字符是小时,最后一个字符是日期。
示例:
1001030180015062016
表示:用户 100103 在 2016 年 6 月 15 日 18:00
退出 (0)
该文件包含多个用户的数据,可以包含一个或多个月的数据。
awk 是否可以像这样为每个用户和每个月(csv 或 excel 文件)生成报告?


USER:100103
Month: 05/2016
date        enter  exit   enter  exit   enter  exit enter exit
25/05/2016  07:58  12:58  14:03  18:01
26/05/2016  07:79  12:59  14:01  18:00         18:00

并且可以将用户名与 ID 相关联(例如 100103 = mike) 获得这样的东西?(也许我可以生成一个 csv table with id; username)

USER:100103 - Mike
Month: 05/2016
date        enter  exit   enter  exit   enter  exit enter exit
25/05/2016  07:58  12:58  14:03  18:01
26/05/2016  07:79  12:59  14:01  18:00         18:00


awk 是否可行或有最简单的方法?

Awk 有一种数据结构,arrays,它基本上是从字符串到 Awk 值的字典。数组始终是一维的,但您可以通过在索引中写入逗号来 "cheat",这会扩展为变量 SUBSEP(下标分隔符)的值,默认情况下 "4"。所以 arr["foo", "bar", "zonk"]arr["foo" SUBSEP "bar" SUBSEP "zonk"].

是一样的

由于您无法扫描数组以查找特定下标的所有键,因此在您的应用程序中,您可能希望填写 table 个 exit/entry 日期加上额外的 table 让你知道哪个出口是哪个人的。

假设您已经将一行拆分为字段并将它们转换为适当的值,这可能如下所示:

/* assuming `user` is set to the six-digit ID code,
            `datetime` is set to whichever format you prefer,
            `direction` is one of "enter" or "exit" */
{
    i = ++nr_access_by_user[user]
    access_times[user, i] = datetime
    access_direction[user, i] = direction
}

END
{
    /* assuming you have already identified a specific value for `user`
       whose activity you want to log, and a function called `relevant`
       which determines if the access time comes from the day you want
       to log */
    for (i = 1; i <= nr_access_by_user[user]; i++)
    {
        if (relevant(access_times[user, i]))
        {
            print(access_times[user, i], access_direction[user, i])
        }
    }
}

希望这能为您提供生成所需特定输出格式的指导。

The AWK Programming Language 是该语言的创建者编写的一本优秀书籍,其中详细介绍了此类任务。如果你有机会,我强烈推荐阅读它。 编辑: Ed Morton 指出这本书已经严重过时,并推荐 Arnold Robbins 编写的 Effective Awk Programming,第 4 版。我是从 The AWK PL 学习的,所以可能有几个我不知道的现代 Awk 的相关特性。

这里开始使用 GNU awk 作为第三个参数来 match() 和 true multi-dimensional 数组:

$ cat tst.awk
BEGIN { OFS="," }
NR==FNR { id2nm[] = ; next }
match([=10=],/(.{6})(.)(.{4})(..)(..)(.*)/,a) {
    id=a[1]; act=a[2]; time=a[3]; day=a[4]; mth=a[5]; yr=a[6]

    sub(/../,"&:",time)

    if (act == 1) {
        ++numEvents[id][yr][mth][day]
    }

    eventNr = numEvents[id][yr][mth][day]
    events[id][yr][mth][day][eventNr][act] = time
}
END {
    print "ID", "Name", "Year", "Month", "Day", "Enter", "Exit", "..."
    for (id in events) {
        for (yr in events[id]) {
            for (mth in events[id][yr]) {
                for (day in events[id][yr][mth]) {
                    printf "%s%s%s%s%s%s%s%s%s", id, OFS, id2nm[id], OFS, yr, OFS, mth, OFS, day
                    num = numEvents[id][yr][mth][day]
                    for (eventNr=1; eventNr<=num; eventNr++) {
                        enterTime = events[id][yr][mth][day][eventNr][1]
                        exitTime  = events[id][yr][mth][day][eventNr][0]
                        printf "%s%s%s%s", OFS, enterTime, OFS, exitTime
                    }
                    print ""
                }
            }
        }
    }
}

.

$ awk -f tst.awk names log
ID,Name,Year,Month,Day,Enter,Exit,...
100103,Mike,2016,05,25,07:58,12:58,14:03,18:01
100103,Mike,2016,05,26,07:59,12:59,14:01,18:00
100104,Sue,2016,05,25,08:02,18:00
100104,Sue,2016,05,26,08:02,

$ awk -f tst.awk names log | column -s, -t
ID      Name  Year  Month  Day  Enter  Exit   ...
100103  Mike  2016  05     25   07:58  12:58  14:03  18:01
100103  Mike  2016  05     26   07:59  12:59  14:01  18:00
100104  Sue   2016  05     25   08:02  18:00
100104  Sue   2016  05     26   08:02

恕我直言,你应该只生成 CSV,而不是将 ID 和名称分成某种 header,你应该使用 YYYYMMDD 年份格式,这样你就可以轻松地按日期排序,但你可以将上面的内容修改为如果你喜欢的话。您需要添加逻辑来处理没有进入的退出或您关心的任何其他事情identify/report/handle。