【问题标题】:awk for generating Report from logfile用于从日志文件生成报告的 awk
【发布时间】:2016-05-24 11:44:16
【问题描述】:

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

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) 获得这样的东西?(也许我可以生成一个带有 id 的 csv 表;用户名)

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 或有最简单的方法?

【问题讨论】:

  • 我尝试使用 excel 数据透视表但没有成功,使用 awk 我将单个字段拆分为不同的字段,但我不知道如何操作不同行的数据并在单行中组织以获得当天进出境

标签: logging awk report data-manipulation


【解决方案1】:

这是使用 GNU awk 的第 3 个参数来匹配()和真正的多维数组的开始:

$ cat tst.awk
BEGIN { OFS="," }
NR==FNR { id2nm[$1] = $2; next }
match($0,/(.{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 和名称分隔到某种标题中,并且您应该使用 YYYYMMDD 年份格式,以便您可以轻松按日期排序,但您可以根据需要调整上述内容。您需要添加逻辑来处理没有输入的退出或您关心识别/报告/处理的任何其他内容。

【讨论】:

  • 我使用了上面的脚本.. 在 99% 的情况下都可以工作,但是如果一天内一个用户没有进入但只有退出没有打印出来......有没有办法解决这个问题?
  • 当然(我在回答的最后一段中说过)但是您应该考虑一下并尝试自己修复它。您需要的所有 awk 语法和语言结构都包含在问题中,因此我希望您可以自己做,但至少想出算法和伪代码。随时提问。
【解决方案2】:

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

由于您无法扫描特定下标的所有键的数组,因此在您的应用程序中,您可能需要填写一个退出/进入日期表以及其他表格,以便您确定哪些退出是由哪个人执行的.

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

/* 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])
        }
    }
}

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

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

【讨论】:

  • 仅供参考 GNU awk 确实有真正的多维数组,请参阅Arrays-of-Arrays。不要使用 The AWK Programming language,因为它已经过时了。 Get Effective Awk Programming,第 4 版,由 Arnold Robbins 撰写,描述了所有现代 POSIX 结构以及 gawk 扩展。
猜你喜欢
  • 2017-07-02
  • 2017-12-21
  • 1970-01-01
  • 2011-01-28
  • 2015-10-20
  • 1970-01-01
  • 2015-10-13
  • 1970-01-01
  • 2022-11-22
相关资源
最近更新 更多