I need a script which shows a summary of which users have connected to my computer during the last week and how often.
I know I can use last
and filter the
Try this
Steps
last > login.txt
last | awk '{print $3}' | sort -u > names.txt
Iterate each lines from names.txt and apply grep "line1" login.txt | wc -l
you will get count for each user (each user is each line in names.txt)
I strongly advise against parsing the output of last
, as its output may differ from implementation to implementation and parsing the login/logout dates is prone to error. Also, it seems that nearly all implementations don't support -F
or similar which without you are completely out of luck, as you need the year information. In theory you could check if there is a leap from one month to another one that is more recent on two consecutive lines (e.g. Jan->Dec would indicate a year change), but this heuristic is flawed - you just cannot guess the correct year(s) correctly. For example, take the rare case that nobody logged in for a year.
If you absolutely have to/want to parse its output either way, don't do it with just bash/awk/cut/... for the reasons above. To get the session duration you would either have to parse the prettyprinted login/logout dates yourself or the already calculated duration, which is also prettyprinted and probably varies from implementation to implementation (as in, it's not just hours and minutes. How do get days/weeks/years represented in that column?). Doing this with just bash/awk would be a nightmare and even more prone to breakage than my script below - please don't do it.
The best and least hacky solution would involve writing a small C program or script that operates on the wtmp
data directly (man wtmp
), but then you would have to calculate the session durations yourself based on login/logout pairs (you don't get this for free; login is one record, logout is a second one). See busybox' last implementation for a reference on how it reads its stuff. This is the way to go if you want to do it the right way.
That being said, I came up with the quick'n'dirty (perl) solution below. It doesn't run the last
command, you have to feed it proper input yourself, otherwise it will explode. If your last
output looks different than mine, doesn't support -F
or Date::Parse
cannot parse the format your last
command prints, it will also explode. There is lots of room for improvement, but this should get you started.
-F
is required for last
to print full dates (we need this to get the year, otherwise we cannot determine proper timestamps from its output)-i
tells last to output IP addresses, which just makes its output easier to parseDate::Parse
, which means that it has to exclude all sessions that don't have a proper login/logout date (i.e., they are still logged in or their session got terminated due to a reboot, crash, etc.), so these sessions won't be part of the calculated output!-d
switch#!/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)
$