I am a bash beginner and I need to write an script to check my users login time. This has to be in a format of :
This script has to work on a server to check all the users. I know that I have to use "last" command but I have no idea how to do it.
any assistance is appreciated.
Thanks
That does something similar to what you seem to need. You'll have to modify the output to meet your needs, and drop the 'last day' limitation (should actually make it less complicated); at the least it should give you an idea about how to use the last command to do what you want.
---------- Post updated at 01:47 PM ---------- Previous update was at 10:57 AM ----------
Well, apparently it doesn't work that way though. I need to get the files from /var/log with .bz2 extension and decompress them. this is where "last" command access and reads the wtmp file to get data when you use "finger" command.
The question is: without sudo or su permission how can I decompress thos bz2 files and put all of them together. because there are plenty of them in /var/log
Thanks.
Really? Using last under linux, and the script below, I can generate exactly what you described in your original post. If you're running on FreeBSD, then the fields are organised differently, and last accepts different options, but the information is the same and can be parsed and presented without having to have root access.
User: scooter
Start: Tue Feb 14 22:33:16
End: Wed Feb 15 00:07:52
Time On: 01:34
Remote Host: localhost
User: scooter
Start: Sun Feb 12 12:52:49
End: Sun Feb 12 12:55:21
Time On: 00:02
Remote Host: liz
I have 2 questions:
1- How did you learn bash scripting so well?
2- I have to look at the whole /var/log/wtmp files. There are so many of them and I have to add them to one file but I can't this is what I did:
# Check for existing /tmp/tst folder
if [ "/tmp/tst" != "" ]; then
rm -rf /tmp/tst
# Make a directory in /tmp called tst
mkdir -p /tmp/tst
# Copy wtmp files in /tmp/tst folder and unzip them:
cp -f /var/log/wtmp* /tmp/tst/
fi
bzip2 -d /tmp/tst/wtmp-*.bz2 | last -f wtmp-* > wtmpfile
cat wtmpfile
Then I have to add all the logged time of my users together and give a total as output. In your script you just used "last" command. which gives you only information from present machine not all other servers on the network.
correct me if I am wrong....
Lots of practice. I've been writing code for a very long time now, and still learn something with nearly every post.
I see. I didn't grock that you needed to produce output based on all of them, and not just from the most recent.
I think you are on the right track. You might find this a bit easier to manage:
#!/usr/bin/env ksh
cd /tmp # safe place to work
tfile=/tmp/wtmp.$$ # temp file to uncompress into
big_file=/tmp/$USER.wtmp #collect all output from wtmp into one file
ls /var/tmp/wtmp*bz2 | while read file # for each wtmp file
do
bunzip2 -dc $file >$tfile # uncompress writing output to tmp file
last -F -a -f $tfile # run last on it
done >$big_file # save all output from last in one file
last -F -a >>$big_file # append formatted output from current wtmp
rm $tfile # tmp file not needed
### parse your big file (/tmp/$USER.wtmp) here #####
# cleanup before exit
rm $big_file
This unzips each bzipped wtmp file directly to a temporary file, and then immediately runs last on it collecting all of the output in one file. A final last is executed which uses the current wtmp file and appends that output to the big file. You can then parse the big file as needed. You won't need a temporary directory because you don't have to copy the files.
#!/bin/bash
if [ $# -ne 1 ]; then
echo Usage: timeon username
exit 1
fi
if [ $# -eq 1 ]
then
user=$1
# else
# user=$USER
fi
# check if the user exists on Matrix
a=$(ypcat passwd | grep -w ^$user)
if [ "$a" == "" ]
then
echo "$user does not exist on Matrix, try again." >&2
exit 2
elif [ "$a" != "" ]; then
# get the username
username=$(echo $a | cut -d: -f1)
echo Username: $username
fi
# Check for existing /tmp/tst folder
if [ "/tmp/tst" != "" ]; then
rm -rf /tmp/tst
# Make a directory in /tmp called tst
mkdir -p /tmp/tst
fi
# Copy wtmp files in /tmp/tst folder and unzip them:
cd /tmp/tst # safe place to work
tfile=/tmp/tst/wtmp.$$ # temp file to uncompress into
big_file=/tmp/tst/$USER.wtmp #collect all output from wtmp into one file
ls /var/log/wtmp*bz2 | while read file # for each wtmp file
do
bunzip2 -dc $file >$tfile # uncompress writing output to tmp file
last -F -a -f $tfile # run last on it
done >$big_file # save all output from last in one file
last -F -a >>$big_file # append formatted output from current wtmp
rm $tfile # tmp file not needed
### parse your big file (/tmp/$USER.wtmp) here #####
# cleanup before exit
#rm $big_file
b=$( cat /tmp/tst/$USER.wtmp | grep $user )
echo $b
but what I get as the output is some data that I don't know how to add them up for the followings:
Start Date: Sept 27, 2011 End Date : Jan 26, 2012 Time On : 31hrs 12min
I know that I have to use grep and bc but don't know how.
This is the example of my output:
You've got a good start. You're getting lots of 'jumbled' output because you are assigning it to a variable and that's messing with newlines. Try adding this to the end of your script instead of the last two lines (it's from earlier in the tread with the last command replaced with the grep):
# your script as you have it up to here....
# cleanup before exit
#rm $big_file
grep $user /tmp/tst/$USER.wtmp | awk '
/wtmp begins/ { next; }
/still logged in/ { next; }
$0 == reboot { next; }
NF > 0 {
if( NR > 1 )
printf( "\n" );
printf( " User:\t%s\n", $1 ); # user
printf( " Start:\t%s %s %s %s\n", $3, $4, $5, $6 );
if( $9 == "down" )
printf( " End:\tshutdown\n" );
else
printf( " End:\t%s %s %s %s\n", $9, $10, $11, $12 );
if( substr( $NF, 1, 1 ) == "(" )
{
t = $NF;
h = "localhost";
}
else
{
t = $(NF-1);
h = $NF;
}
gsub( "[()]", "", t );
printf( " Time On:\t%s\n", t );
printf( "Remote Host:\t%s\n", h );
} '
This will format each entry from the huge wtmp output for the given user. If you need a total time, or a single entry with totals instead of one per login, then the awk will need to be changed or replaced with something you are more comfortable with. Adding this, and running it, I think will let you see how you need to go forward with the grep and processing the complete wtmp output.
You are awesome! Thank You!
it is a fantastic piece of code but, I never worked with awk and it is getting too complicated for me. is there anyway you simplify this for me with use of grep? I need the:
Start Date
End Date
Time On in minutes
You can try adding a sort after the grep in the pipeline. This will sort based on the start login time and write the most recent events first. In addition, add an exit after you print the first bit of data. This will allow any 'still logged in' records to be discarded, and will print the last complete session for the user.
---------- Post updated at 13:29 ---------- Previous update was at 13:26 ----------
I forgot to mention that you might want to tighten up the sort a bit. It sorts based on year, month, day and hour, but doesn't take into account minutes, so if a user logged in and out twice in the same hour, you might not get the most recent one.
=================================================
I really appreciate your help. I changed the script so I can handle it with my own knowledge. Your script is very professional and I didn't understand the whole script. I attached the part that I did on my own here however, I need to calculate the TIME ON as well. I would like to use "bc". could you help me with that too?
leng=`expr length "$username"`
# if username length is more than 8 characters print an error.
if [ $leng -gt 8 ]; then
new_username=$(echo $username | cut -c 1-8)
else
new_username=$username
fi
ls /var/log/wtmp*bz2 | while read file # for each wtmp file
do
bunzip2 -dc $file >$tfile # uncompress writing output to tmp file
last -F -a -f $tfile # run last on it
done >$big_file # save all output from last in one file
last -F -a >>$big_file # append formatted output from current wtmp
rm $tfile # tmp file not needed
echo $big_file | egrep $new_username /tmp/tst/$USER.wtmp > /tmp/tst/mytst
# The Start Date Calculation
st_dat=$(cat /tmp/tst/mytst | head -1 | cut -c 27-32)
st_dat1=$(cat /tmp/tst/mytst | head -1 | cut -c 43-46)
st_dat2=$(echo $st_dat", "$st_dat1)
echo Start Date: $st_dat2 # THIS IS THE START DATE OUTPUT
# The End Date Calculation
end_dat=$(cat /tmp/tst/mytst | tail -1 | cut -c 53-59)
end_dat1=$(cat /tmp/tst/mytst | tail -1| cut -c 70-75 )
end_dat2=$(echo $end_dat", "$end_dat1)
echo End Date: $end_dat2 # THIS IS THE START DATE OUTPUT
---------- Post updated at 04:41 PM ---------- Previous update was at 04:38 PM ----------
This is a sample of my output in a txt file that I need to calculate the TIME ON from: