Awk:给定具有会话数据的用户列表,输出具有特定数据的用户列表

时间:2017-03-05 16:17:05

标签: linux awk

不确定如何提出这个问题,因此我不知道如何在Google或SO上搜索它。让我告诉你给定的数据。顺便说一句,这只是一个Awk练习,它不是功课。一直试图解决这个问题2天。以下是一个例子;

Mon Sep 15 12:17:46 1997
User-Name = "wynng"
NAS-Identifier = 207.238.228.11
NAS-Port = 20104
Acct-Status-Type = Start
Acct-Delay-Time = 0
Acct-Session-Id = "239736724"
Acct-Authentic = RADIUS
Client-Port-DNIS = "3571800"
Framed-Protocol = PPP
Framed-Address = 207.238.228.57

Mon Sep 15 12:19:40 1997
User-Name = "wynng"
NAS-Identifier = 207.238.228.11
NAS-Port = 20104
Acct-Status-Type = Stop
Acct-Delay-Time = 0
Acct-Session-Id = "239736724"
Acct-Authentic = RADIUS
Acct-Session-Time = 115
Acct-Input-Octets = 3915
Acct-Output-Octets = 3315
Acct-Input-Packets = 83
Acct-Output-Packets = 66
Ascend-Disconnect-Cause = 45
Ascend-Connect-Progress = 60
Ascend-Data-Rate = 28800
Ascend-PreSession-Time = 40
Ascend-Pre-Input-Octets = 395
Ascend-Pre-Output-Octets = 347
Ascend-Pre-Input-Packets = 10
Ascend-Pre-Output-Packets = 11
Ascend-First-Dest = 207.238.228.255
Client-Port-DNIS = "3571800"
Framed-Protocol = PPP
Framed-Address = 207.238.228.57

因此日志文件包含各种用户的上述数据。我特意粘贴这个以显示该用户有登录,Acct-Status-Type = Start和注销,Acct-Status-Type = Stop。这算作一个会话。因此,我需要生成以下输出。

User:           "wynng"
Number of Sessions: 1
Total Connect Time: 115
Input Bandwidth Usage:  83
Output Bandwidth Usage: 66

我遇到的问题是保持信息以某种方式附加到用户身上。当会话处于停止状态时,日志文件中的每个条目都具有相同的信息,因此我只能使用正则表达式

/ Acct-Input-Packets / {inPackets = $ 3}

/ Acct-Output-Packets / {outPackets = $ 3}

每次迭代数据都会覆盖过去的值。 我想要做的是,如果我找到一个用户名条目并且此条目有一个停止,那么我想为该用户记录输入/输出数据包值。这是我难倒的地方。

对于会话值,我考虑将用户名保存在一个数组中,然后在END {}中计算重复项,并除以2,如果是偶数则大于2。如果奇数然后除以2然后将它放下。

我不一定想得到答案,但也许是一些提示/指导,或者也许是一个我可以扩展的简单例子。

1 个答案:

答案 0 :(得分:1)

您可以查看以下各行:

  • 日期模式:/\w+\s\w+\s[0-9]{2}\s[0-9]{2}:[0-9]{2}:[0-9]{2}\s[0-9]{4}/
  • 用户名值:/User-Name\s+=\s+\"\w+\"/
  • 状态值:/Acct-Status-Type\s+=\s+\w+/
  • 输入数据包值:/Acct-Input-Packets\s+=\s[0-9]+/
  • 输出数据包值:/Acct-Output-Packets\s+=\s[0-9]+/
  • 一个空行:/^$/

一旦你定义了你想要的东西(上面的模式),它只是条件的问题,并将所有这些数据存储在某个数组中。

在下面的示例中,我将上面的每个值类型存储在每个类型的专用数组中,其中count索引在检测到空行/^$/时递增:

awk 'BEGIN{
    count = 1;
    i = 1;
}{
    if ($0 ~ /\w+\s\w+\s[0-9]{2}\s[0-9]{2}:[0-9]{2}:[0-9]{2}\s[0-9]{4}/){
        match($0, /\w+\s(\w+)\s([0-9]{2})\s([0-9]{2}):([0-9]{2}):([0-9]{2})\s([0-9]{4})/, n);
        match("JanFebMarAprMayJunJulAugSepOctNovDec",n[1])
        n[1] = sprintf("%02d",(RSTART+2)/3);
        arr[count]=mktime(n[6] " " n[1] " " n[2] " " n[3] " " n[4] " " n[5]);
        order[i]=count;
        i++;
    }
    else if ($0 ~ /User-Name\s+=\s+\"\w+\"/){
        match($0, /User-Name\s+=\s+\"(\w+)\"/, n);
        name[count]=n[1];
    }
    else if ($0 ~ /Acct-Status-Type\s+=\s+\w+/){
        match($0, /Acct-Status-Type\s+=\s+(\w+)/, n);
        status[count]=n[1];
    }
    else if ($0 ~ /^$/){
        count++;
    }
    else if ($0 ~ /Acct-Input-Packets\s+=\s[0-9]+/){
        match($0, /Acct-Input-Packets\s+=\s([0-9]+)/, n);
        input[count]=n[1];
    }
    else if ($0 ~ /Acct-Output-Packets\s+=\s[0-9]+/){
        match($0, /Acct-Output-Packets\s+=\s([0-9]+)/, n);
        output[count]=n[1];
    }
}
END{
    for (i = 1; i <= length(order); i++) {

        val = name[order[i]];

        if (length(user[val]) == 0) {

            valueStart = "0";

            if (status[order[i]] == "Start"){
                valueStart = arr[order[i]];
            }
            user[val]= valueStart "|0|0|0|0";
        }
        else {
            split(user[val], nameArr, "|");

            if (status[order[i]]=="Stop"){
                nameArr[2]++;
                nameArr[3]+=arr[order[i]]-nameArr[1]
            }
            else if (status[order[i]] == "Start"){
                # store date start
                nameArr[1] = arr[order[i]];
            }

            nameArr[4]+=input[order[i]];

            nameArr[5]+=output[order[i]];

            user[val]= nameArr[1] "|" nameArr[2] "|" nameArr[3] "|" nameArr[4] "|" nameArr[5];
        }
    }

    for (usr in user) {
        split(user[usr], usrArr, "|");
        print "User: " usr;
        print "Number of Sessions: " usrArr[2];
        print "Total Connect Time: " usrArr[3];
        print "Input Bandwidth Usage: " usrArr[4];
        print "Output Bandwidth Usage: " usrArr[5];
        print "------------------------";

    }
}' test.txt

使用match函数提取值,如:

match($0, /User-Name\s+=\s+\"(\w+)\"/, n);

对于日期,我们必须解析月份字符串部分,我已经使用this post中的解决方案来提取:

match($0, /\w+\s(\w+)\s([0-9]{2})\s([0-9]{2}):([0-9]{2}):([0-9]{2})\s([0-9]{4})/, n);
match("JanFebMarAprMayJunJulAugSepOctNovDec",n[1])
n[1] = sprintf("%02d",(RSTART+2)/3);

收集值的所有处理都在END子句中完成,我们必须对值进行分组,我创建一个user数组,其中username为关键值,值为a由|分隔的所有不同类型的串联:

[startDate] "|" [sessionNum] "|" [connectionTime] "|" [inputUsage] "|" [outputUsage]

使用this data input(您的数据已扩展),它会给出:

User: TOTO
Number of Sessions: 1
Total Connect Time: 114
Input Bandwidth Usage: 83
Output Bandwidth Usage: 66
------------------------
User: wynng
Number of Sessions: 2
Total Connect Time: 228
Input Bandwidth Usage: 166
Output Bandwidth Usage: 132
------------------------