Link to home
Start Free TrialLog in
Avatar of PMG76
PMG76Flag for United States of America

asked on

unix logon summary

I need some help making a program that prints a summary to the screen using the "last" command in Unix.  I need to take the account, terminal, hostname, date (in HH:MM format), login, logout, and duration fields and output the following information formatted like this:  ACCOUNT = LOGINS = TIME.  I'm not sure really how to begin.  I would appreciate some help understanding how to do this.
Avatar of arnold
arnold
Flag of United States of America image

Are you familiar with hashes and hash references?

You effectively are looking at hash of hashes
users{login_name}->{logins}
                             -> {duration}

You would need to convert the duration reported by last (hours:minutes) or (days+hours:minutes) into minutes.

fairly simple to do.
Avatar of PMG76

ASKER

We have not covered hashes yet.  I need to do it without hash references.
You could use two arrays where the login is the array element that will count the number of logins.
and the other array with the login as an element reference is the duration counter.

The other option is to run the last command as many times as there are individual users
I.e first get the list of unique users who ever logged in.
for every user
last |grep user | process data


Avatar of PMG76

ASKER

Could you give me a few lines of sample code so that I have something to build of of?  I'm not sure how to even start reallly.
last | awk ' { print $1 } ' | sort -fu | while read a; do
echo working with user $a:
last | grep $a | perl_script_to_get_user_specificdata.pl #this script will output user:logins:duration
done


#!/usr/bin/perl

while (<STDIN>) {
#$_ will have each line
chomp(); #if exists remove the cr/lf from this line
@array=split(/\s+/,$_)
#$array[1] has the username
#$array[$#array] has the duration
#you need a line counter to count the number of logins.
#you then need to convert the duration reported into minutes and add it to a duration counter. Note the pattern of duration can be (hh:mm) or (d+hh:mm)
#Did you cover pattern match/data extraction?
}
print "User:$array[0] Had $login_count logins for a total duration of $duration_counter\n";

Open in new window

Avatar of PMG76

ASKER

So am i supposed to put this code at the top:

last | awk ' { print $1 } ' | sort -fu | while read a; do
echo working with user $a:
last | grep $a | perl_script_to_get_user_specificdata.pl #this script will output user:logins:duration
done

Then paste lines 1-13 undernearth it?   i am also using strict and it tells me that array and login_count_ are not valid.

We did cover pattern match.  How is that going to be used /.
Avatar of PMG76

ASKER

Here is my exact eror message:

Unquoted string "awk" may clash with future reserved word at ./program7.pl line 29.
String found where operator expected at ./program7.pl line 29, near "awk ' { print $1 } '"
        (Do you need to predeclare awk?)
Unquoted string "a" may clash with future reserved word at ./program7.pl line 29.
Unquoted string "pl" may clash with future reserved word at ./program7.pl line 31.
Unquoted string "done" may clash with future reserved word at ./program7.pl line 32.
syntax error at ./program7.pl line 29, near "awk ' { print $1 } '"
syntax error at ./program7.pl line 30, near "do
echo working with "
Execution of ./program7.pl aborted due to compilation errors.
#!/usr/bin/perl

use warnings;
#use strict;

last | awk ' { print $1 } ' | sort -fu | while read a; do
echo working with user $a:;
last | grep $a | perl_script_to_get_user_specificdata.pl; #this script will output user:logins:duration
done;



while (<STDIN>) {
#$_ will have each line
chomp(); #if exists remove the cr/lf from this line
my @array=split(/\s+/,$_);
#$array[1] has the username
#$array[$#array] has the duration
#you need a line counter to count the number of logins.
#you then need to convert the duration reported into minutes and add it to a duration counter. Note the pattern of duration can be (hh:mm) or (d+hh:mm)
#Did you cover pattern match/data extraction?
}
print "User:$array[0] Had @$login_count_ logins for a total duration";
~

Open in new window

The two are two separate scripts.
awk and everything that follows is a bash/shell script
#!/bin/sh

last | awk ' { print $1 } ' | sort -fu | while read a; do
echo working with user $a:;
last | grep $a | perl_script_to_get_user_specificdata.pl; #this script will output user:logins:duration
done;

The other processor is a perl script
Note that last and the perl script will run as many times as there are unique users in last.
Oh, for strict you have to define the variables that will be used using
my $variable # at the top for global use variable or within the if/while as a local variable that will be redifined upon every entry into the if/while etc. block.

You need to use pattern match to extract the data from the duration.
i.e. how are you planning on adding an entry (03:23) and (2+02:20)?
You have to extract the information and convert it to a common unit.
usera pts/0 location date (03:23)
usera pts/1 location2 date (2+02:20)
What is the information for usera?
usera had 2 logins for a duration of 2days 5 hours and 43 minutes. or 3223 minutes or 53 hours and 43 minutes.
Avatar of PMG76

ASKER

We haven't covered scripts yet.  I need everything to run and process in the Perl program.
Or you can use last | sort | perlscript
Note that in this case you have to check whether the user in the current line is the same as the user in the prior line. If it is not, you need to output data for the prior user and reset the counters and the user for the current user then continue processing.

Or

use
open LAST,"/usr/bin/last| awk ' { print $1 } ' | sort -fu " || die "Unable to run last command:$!\n;
while ($user=<LAST>) {
chomp($user);
open LAST3,"/usr/bin/last| grep $user |" || die "Unable to run last command a second time (inner loop):$!\n;

while (<LAST3>) {
chomp();
#process data here



} #close inner loop
close (LAST3)
print "user: $user Number of logins: $logins Duration: $duration\n";

} #close outer loop
close (LAST)
Avatar of PMG76

ASKER

Ok. I tried to modify it and this is what Im getting now":

Unquoted string "usr" may clash with future reserved word at ./program7.pl line 10.
Unquoted string "bin" may clash with future reserved word at ./program7.pl line 10.
Bareword found where operator expected at ./program7.pl line 10, near "" || die "Unable"
        (Missing operator before Unable?)
Unquoted string "run" may clash with future reserved word at ./program7.pl line 10.
Bareword found where operator expected at ./program7.pl line 10, near "last command a"
        (Do you need to predeclare last?)
Backslash found where operator expected at ./program7.pl line 10, near "$!\"
        (Missing operator before \?)
Unquoted string "n" may clash with future reserved word at ./program7.pl line 10.
Not enough arguments for grep at ./program7.pl line 10, near "" || die "Unable to "
syntax error at ./program7.pl line 10, near "" || die "Unable to "
Unmatched right curly bracket at ./program7.pl line 31, at end of line
syntax error at ./program7.pl line 31, near "}"
Unmatched right curly bracket at ./program7.pl line 35, at end of line
Execution of ./program7.pl aborted due to compilation errors.

#!/usr/bin/perl


use warnings;
#use strict;

open LAST,"/usr/bin/last| awk ' { print $1 } ' | sort -fu " || die "Unable to run last command:$!\n;
while ($user=<LAST>) {
chomp($user);
open LAST3,"/usr/bin/last| grep $user |" || die "Unable to run last command a second time (inner loop):$!\n;

while (<LAST3>) {
chomp();
#process data here



#while (<STDIN>) {
#$_ will have each line
#chomp(); #if exists remove the cr/lf from this line
my @array=split(/\s+/,$_);
#$array[1] has the username
#$array[$#array] has the duration
#you need a line counter to count the number of logins.
#you then need to convert the duration reported into minutes and add it to a duration counter. Note the pattern of duration can be (hh:mm) or (d+hh:mm)
#Did you cover pattern match/data extraction?
}

print "User:$array[0] Had @$login_count_ logins for a total duration";

} #close inner loop
close (LAST3)
print "user: $user Number of logins: $logins Duration: $duration\n";

} #close outer loop
close (LAST);
~

Open in new window

I've provided you with almost a step by step what you need to consider to get the results you want. can you provide a sample of code that you worked out?
I have a fully functional perl script that uses hash of hashes to go through.

Using last | sort | perl_script should be fairly simple to create.

What you need to know in perl is while (<STDIN>) {}
To go line by line. You then have to make sure to check whether the user reported in this line is the same as the user from the prior line.
You need to use split, the break up the line into its informational sections, username, duration.
You need to use pattern match to extract the relavent data from the duration so that you can then convert the reported duration into minutes.

the first occurance where the current user does not match the prior user, you must output the prior user's information and reset the counts.

ASKER CERTIFIED SOLUTION
Avatar of arnold
arnold
Flag of United States of America image

Link to home
membership
This solution is only available to members.
To access this solution, you must be a member of Experts Exchange.
Start Free Trial