Solved

unix logon summary

Posted on 2010-09-22
14
277 Views
Last Modified: 2012-05-10
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.
0
Comment
Question by:PMG76
  • 8
  • 6
14 Comments
 
LVL 76

Expert Comment

by:arnold
ID: 33738171
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.
0
 

Author Comment

by:PMG76
ID: 33738489
We have not covered hashes yet.  I need to do it without hash references.
0
 
LVL 76

Expert Comment

by:arnold
ID: 33738776
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


0
 

Author Comment

by:PMG76
ID: 33743223
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.
0
 
LVL 76

Expert Comment

by:arnold
ID: 33743874
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

0
 

Author Comment

by:PMG76
ID: 33754639
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 /.
0
 

Author Comment

by:PMG76
ID: 33754758
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

0
How to run any project with ease

Manage projects of all sizes how you want. Great for personal to-do lists, project milestones, team priorities and launch plans.
- Combine task lists, docs, spreadsheets, and chat in one
- View and edit from mobile/offline
- Cut down on emails

 
LVL 76

Expert Comment

by:arnold
ID: 33754856
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.
0
 
LVL 76

Expert Comment

by:arnold
ID: 33754920
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.
0
 

Author Comment

by:PMG76
ID: 33754930
We haven't covered scripts yet.  I need everything to run and process in the Perl program.
0
 
LVL 76

Expert Comment

by:arnold
ID: 33755042
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)
0
 

Author Comment

by:PMG76
ID: 33755582
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

0
 
LVL 76

Expert Comment

by:arnold
ID: 33756730
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.

0
 
LVL 76

Accepted Solution

by:
arnold earned 500 total points
ID: 33756786
Oh,
an extraction using a pattern match
$string="The line is - and has been - this one."
Lets say you want the data in between the dashes (-)
if ( $string=~ /^.*\-(.*)\-.*$/) {
       $entry_of_interest=$1;
}

in a pattern match anything in parenthesis () that is matched is assign to a variable in the order of occurance starting from one
if ($string=~ /(pattern)(pattern2)(patern3)(pattern4)(pattern5)/ ) {
If the pattern matched all there will be data in :
$1 based on pattern
$2 based on pattern2
$3 based on pattern3
$4 based on pattern4
$5 based on pattern5

They are all set or non are set i.e. the total pattern matching criteria did not match.

0

Featured Post

Free Trending Threat Insights Every Day

Enhance your security with threat intelligence from the web. Get trending threat insights on hackers, exploits, and suspicious IP addresses delivered to your inbox with our free Cyber Daily.

Join & Write a Comment

Many time we need to work with multiple files all together. If its windows system then we can use some GUI based editor to accomplish our task. But what if you are on putty or have only CLI(Command Line Interface) as an option to  edit your files. I…
Email validation in proper way is  very important validation required in any web pages. This code is self explainable except that Regular Expression which I used for pattern matching. I originally published as a thread on my website : http://www…
Learn how to navigate the file tree with the shell. Use pwd to print the current working directory: Use ls to list a directory's contents: Use cd to change to a new directory: Use wildcards instead of typing out long directory names: Use ../ to move…
In a previous video, we went over how to export a DynamoDB table into Amazon S3.  In this video, we show how to load the export from S3 into a DynamoDB table.

705 members asked questions and received personalized solutions in the past 7 days.

Join the community of 500,000 technology professionals and ask your questions.

Join & Ask a Question

Need Help in Real-Time?

Connect with top rated Experts

22 Experts available now in Live!

Get 1:1 Help Now