使用awk获取给定用户的最长登录时间

Get the longest logon time of a given user using awk

我的任务是编写一个 bash 脚本,使用 awk 来查找给定用户的最长登录时间(“仍然登录”不算在内),并打印 month day IP logon time in minutes.

示例输入:./scriptname.sh username1

last username1内容:

username1       pts/        IP      Apr     2       ..      ..      ..      ..      (00.03)

username1       pts/        IP      Apr     3       ..      ..      ..      ..      (00.13)

username1       pts/        IP      Apr     5       ..      ..      ..      ..      (12.00)

username1       pts/        IP      Apr     9       ..      ..      ..      ..      (12.11)

示例输出:

Apr 9 IP 731 (expl: 12小时11分钟共计731分钟)

我写了这个脚本,但是弹出一堆错误,我真的很困惑:

#!/bin/bash

usr=

last $usr | grep -v "still logged in" | awk 'BEGIN {max=-1;}
                                                {
                                                h=substr(,2,2);
                                                min=substr(,5,2) + h/60;
                                                }
                                                (max < min){
                                                max = min;
                                                }
                                                END{
                                                maxh=max/60;
                                                maxmin=max-maxh;
                                                ($maxh == 0 && $maxmin >=10){
                                                        last $usr | grep "00:$maxmin" | awk '{print ," ",," ", ," ",$maxmin}'
                                                        exit 1
                                                }
                                                ($maxh == 0 $$ $maxmin < 10){
                                                        last $usr | grep "00:0$maxmin" | awk '{print ," ",," ",," ",$maxmin}'
                                                        exit 1
                                                }
                                                ($maxh < 10 && $maxmin == 0){
                                                        last $usr | grep "0$maxh:00" | awk '{print ," ",," ",," ",$maxmin}'
                                                        exit 1
                                                }
                                                ($maxh < 10 && $maxmin < 10){
                                                        last $usr | grep "0$maxh:0$maxmin" | awk '{print ," ",," ",," ",$maxmin}'
                                                        exit 1
                                                }
                                                ($maxh >= 10 && $maxmin < 10){
                                                        last $usr | grep "$maxh:0$maxmin" | awk '{print ," ",," ",," ",$maxmin}'
                                                        exit 1
                                                }
                                                ($maxh >=10 && $maxmin >= 10){
                                                        last $usr | grep "$maxh:$maxmin" | awk '{print ," ",," ",," ",$maxmin}'
                                                        exit 1
                                                }
                                                }'

所以稍微解释一下我想象中的效果:

初始化后,我想找到last $usr命令的(hh:mm)列,保存每一行的hmin,找到最大的数(以分钟为单位,意味着它是最长的登录时间)。

找到最长登录时间后(以分钟为单位,存储在变量 max 中),然后我必须将唯一的分钟格式重新格式化为 hh:mm 才能使用 grep,再次使用上一个命令,但现在只搜索包含 max 登录时间的行,并在 month day [=14= 中打印所有需要的信息] logon time in minutes格式,使用另一种awk.

我在 运行 这段代码 时得到的错误:当我尝试在原始代码中使用 grepawk 时出现一堆语法错误awk.

如果 gnu-awk 可用,您可以对最后一个字段中的数字使用包含 2 个捕获组的模式。在 END 块中打印您想要的格式。

如果在此示例中,file包含示例内容,并且最后一列包含登录:

awk '
match ($(NF), /\(([0-9]+)\.([0-9]+)\)/, a) {
  hm = (a[1] * 60) + a[2]
  if(hm > max) {max = hm; line = [=10=];}
}
END {
  n = split(line,a,/[[:space:]]+/)
  print a[3], a[4], a[5], max
}
' file

输出

IP Apr 9 731

awk 不是 shell。您不能直接从 awk 调用 lastgrepawk 之类的工具,就像您不能直接从 C 程序调用它们一样。

在每个 Unix 机器上的任何 shell 中使用任何 awk 并假设多行是否有您想要打印所有这些的最大时间,如果没有找到带时间戳的行,您需要类似 No matching records 打印(如果没有,可以轻松调整,只需告诉我们您对这些情况的要求,并将它们包含在您问题的示例中):

last username1 |
awk '
    /still logged in/ {
        next
    }
    {
        split($NF,t,/[().]/)
        cur = (t[2] * 60) + t[3]
    }
    cur >= max {
        out = ( cur > max ? "" : out ORS )  OFS  OFS  OFS cur
        max = cur
    }
    END {
        print (out ? out : "No matching records")
    }
'
Apr 9 IP 731

正在我的机器上测试 last 命令:

使用红帽 Linux 7.8 得到以下输出:

user0022 pts/1        10.164.240.158   Sat Apr 25 19:32 - 19:47  (00:14)
user0022 pts/1        10.164.243.80    Sat Apr 18 22:31 - 23:31 (1+01:00)
user0022 pts/1        10.164.243.164   Sat Apr 18 19:21 - 22:05  (02:43)
user0011 pts/0        10.70.187.1      Thu Nov 21 15:26 - 18:37  (03:10)
user0011 pts/0        10.70.187.1      Thu Nov  7 16:21 - 16:59  (00:38)
astukals pts/0        10.70.187.1      Mon Oct  7 19:10 - 19:13  (00:03)
reboot   system boot  3.10.0-957.10.1. Mon Oct  7 22:09 - 14:30 (156+17:21)
astukals pts/0        10.70.187.1      Mon Oct  7 18:56 - 19:08  (00:12)
reboot   system boot  3.10.0-957.10.1. Mon Oct  7 21:53 - 19:08  (-2:-44)
IT       pts/0        10.70.187.1      Mon Oct  7 18:50 - 18:53  (00:03)
IT       tty1                          Mon Oct  7 18:48 - 18:49  (00:00)
user0022 pts/1        30.30.30.168     Thu Apr 16 09:43 - 14:54  (05:11)
user0022 pts/1        30.30.30.59      Wed Apr 15 11:48 - 04:59  (17:11)
user0022 pts/1        30.30.30.44      Tue Apr 14 19:03 - 04:14  (09:11)

发现时间格式为 DD+HH:MM 仅当 DD 不为零时出现。

发现还有其他技术用户:ITsystemreboot需要过滤。

建议解决方案:

last | awk 'BEGIN {FS="[ ()+:]*"}
/reboot|system|still/{next}
{ print  OFS  OFS  OFS $(NF-1) + ($(NF-2) * 60) + ($(NF-3) * 60 * 24)}
' |sort -nk 4| head -1

结果:

Apr 15 30.30.30.59 85991