1

我需要一个脚本来显示上周哪些用户连接到我的计算机以及连接频率的摘要。

我知道我可以使用last和过滤时间列awk,但是如何?我必须在上周让每个用户连接并计算连接数加上所有连接的总时间。到目前为止,这是我想出的:

for USER in `last | awk '{print $1}' | sort -u`; do
    echo "Conexiones de $USER:"
    last | grep $USER | wc -l
    # BUT I NEED T COUNT ONLY LAST WEEK AND PRINT TOTAL TIME
done
4

2 回答 2

2

我强烈建议不要解析 的输出last,因为它的输出可能因实现而异,并且解析登录/注销日期容易出错。此外,似乎几乎所有的实现都不支持-F或类似的,没有你完全不走运,因为你需要年份信息。理论上,您可以检查两个连续行上是否存在从一个月到另一个最近的飞跃(例如 Jan->Dec 表示年份变化),但这种启发式方法是有缺陷的 - 您无法猜测正确的年份(s) 正确。例如,以一年没有人登录的罕见情况为例。

如果您绝对必须/想要以任何一种方式解析其输出,请不要仅使用 bash/awk/cut/... 来执行此操作,原因如上所述。要获得会话持续时间,您要么必须自己解析漂亮打印的登录/注销日期,要么解析已经计算的持续时间,这也是漂亮打印的并且可能因实施而异(例如,它不仅仅是小时和分钟。如何获得天数/weeks/years 在该列中表示?)。仅使用 bash/awk 执行此操作将是一场噩梦,甚至比我下面的脚本更容易损坏 - 请不要这样做。

最好和最简单的解决方案是编写一个wtmp直接对数据进行操作的小型 C 程序或脚本man wtmp( ; 登录是一条记录,注销是第二条记录)。有关它如何读取内容的参考,请参阅busybox 的last实现。如果您想以正确的方式进行操作,这就是要走的路。

话虽如此,我想出了下面的快速'n'dirty(perl)解决方案。它不运行last命令,你必须自己输入正确的输入,否则它会爆炸。如果您的last输出看起来与我的不同,不支持-FDate::Parse无法解析您的last命令打印的格式,它也会爆炸。有很大的改进空间,但这应该让你开始。

笔记

  • -F需要last打印完整日期(我们需要它来获取年份,否则我们无法从其输出中确定正确的时间戳)
  • -i告诉 last 输出 IP 地址,这只会使其输出更易于解析
  • 它不解析会话持续时间列,而是解析登录/注销日期,将它们转换为纪元时间并计算差异以获得会话持续时间。除了 using 之外,解析日期没有其他魔法Date::Parse,这意味着它必须排除所有没有正确登录/注销日期的会话(即,它们仍处于登录状态或会话因重启、崩溃等),因此这些会话不会成为计算输出的一部分!
  • 默认为 7 天,但您可以在命令行中使用-d开关更改此设置

代码

#!/usr/bin/perl

use strict;
use warnings;

use Date::Parse;
use Getopt::Std;

our $opt_d;
getopt('d');
my $days = $opt_d || 7;
my $since = time() - (60 * 60 * 24 * $days);

my %data;
while (<>)
{
    chomp;
    next if /ssh|reboot|down|crash|still logged in/;
    # last -Fi gives this on my box
    # username   line        ip   Mon Apr  1 18:17:49 2013 - Tue Apr  2 01:00:45 2013  (06:42)
    my ($user, undef, undef, $date_from, $date_to) = /^(\S+)\s+(\S+)\s+([0-9.]+)\s+([[:alnum:]:\s]+)\s+-\s+([[:alnum:]:\s]+[^\s])\s+\(.+\)/;

    my $time_from = str2time($date_from);
    last if $time_from < $since;
    my $time_to   = str2time($date_to);

    $data{$user}{"count"}++;
    $data{$user}{"duration"} += $time_to - $time_from;

    # print "$user|$line|$ip|$date_from|$date_to\n";
}

print "login history for the last $days day(s):\n\n";

if (keys %data > 0)
{
    foreach my $user (keys %data)
    {
        my $duration = $data{$user}{"duration"};
        printf "%s was logged in %d time(s) for a total of %d day(s), %d hour(s) and %d minute(s)\n",
            $user,
            $data{$user}{"count"},
            ($duration / (24 * 60 * 60)),
            ($duration / (60 * 60 )) % 24,
            ($duration / 60 ) % 60,
    }
}
else
{
    print "no logins during the specified time period\n";
}

示例用法

$ last -Fi | ./last_parse.pl -d 700
login history for the last 700 day(s):

root was logged in 25 time(s) for a total of 36 day(s), 12 hour(s) and 35 minute(s)
foobar was logged in 362 time(s) for a total of 146 day(s), 17 hour(s) and 17 minute(s)
quux was logged in 3 time(s) for a total of 0 day(s), 0 hour(s) and 4 minute(s)
$
于 2013-04-03T16:13:40.120 回答
0

尝试这个

脚步

  1. last > login.txt

  2. last | awk '{print $3}' | sort -u > names.txt

  3. 从 names.txt 迭代每一行并应用grep "line1" login.txt | wc -l

您将获得每个用户的计数(每个用户是 names.txt 中的每一行)

于 2013-04-02T10:04:40.143 回答