Searching the output of last
Larry Wall
lwall at jpl-devvax.jpl.nasa.gov
Mon Apr 29 17:22:06 AEST 1991
In article <1991Apr29.053721.8733 at agate.berkeley.edu> raymond at math.berkeley.edu (Raymond Chen) writes:
: In article <1991Apr29.043041.20454 at casbah.acns.nwu.edu>, navarra at casbah (John 'tms' Navarra) writes:
:
: >how bout setting up a program that... looks thru utmp by doing a last
: >| grep time (might be slow) ... then increments it by one for interval loops.
: ^^^^^^^^^^^^^
: my vote for understatement of the day. It is not unheard
: of for people to be logged in for days at a time. Incrementing by one means
: you have to perform thousands of greps.
:
: [For comp.lang.perlers, the problem is to write a progral called `whenwho'
: which prints out everybody who was logged on at the time indicated on the
: command line.]
:
: Try this. Hacked up in 15 minutes, minimally tested. Part of the
: problem is that you never know if you've searched backwards far
: enough, because there might be someone who has been logged on
: continuously for the past five months. In the original problem,
: however, we are told that the wtmp goes back only as far as around 5am
: the day of the run, so this isn't an issue.
:
[Script that reads wtmp directly omitted.]
If we can assume nobody is logged in overnight (or that records aren't kept),
then I'd just process the output of "last", like this:
#!/usr/bin/perl
$when = sprintf("%02d:%02d", shift =~ /^(\d+):?(\d\d)$/);
$today = (localtime())[3];
open(LAST, "last |");
while (<LAST>) {
next if length() < 60;
($date,$in,$out) = unpack(x44A2xA5x3A5,$_);
last if $date != $today;
print if $when ge $in && $when le $out;
}
Not quite a one-liner, but getting closer... Hmm... If we throw out the
claptrap to check for todayness, and force people to enter exactly \d\d:\d\d
for the time, we can say
$w=shift;@ARGV="last|";$w ge substr($_,47,5)&&$w lt substr($_,55)&&print while<>
Hmm... No reason not to use a regular expression...
$w=shift;@ARGV="last|";/.{47}(.{5})...(.*)/&&$w ge$1&&$w lt$2&&print while<>
Hmm... We can dump two of those spaces that separate alphanumeric tokens...
$$=shift;@ARGV="last|";/.{47}(.{5})...(.*)/&&$$ge$1&&$$lt$2&&print while<>
Hmm... We can assume that the first field contains the first colon...
$$=shift;@ARGV="last|";/(..:..)...(.*)/&&$$ge$1&&$$lt$2&&print while<>
I don't see how to make that shorter, offhand. At least not in Perl alone.
Combining with shell, we can say
last|perl -pe '$_ x=/(..:..)...(.*)/&&"'$1'"ge$1&&"'$1'"lt$2'
That's gonna be tough for Randal to beat... :-)
Larry
More information about the Comp.unix.questions
mailing list