I would like to make a shell script such that it runs the " last -a " command and summarizes it's data in the form :

userID : number of login sessions
            Host or ip1 - number of connections
            Host or ip2 - number of connections 

I'm trying to do this with "grep" and "awk" but I'm still not able obtain the desired output :(

Edit: My progress To count user instances and their sessions:

 lasta=$(last -a)
 p1=$(echo "$lasta" | awk '{print $1}' | awk '{count[$1]++}END{for(j in count) print j,": "count[j]}')      
 echo "$p1"

This is probably incorrect (counting ip or host ID instances)

uniqueusers=$(echo "$lasta"| awk '{print $1}'| sort | uniq)
p2=$(echo "$lasta" | grep "$uniqueusers" | awk '{print $10 } ' | awk '{count[$1]++}END{for(j in count) print j,": "count[j]}')
echo "$p2"
  • 1
    Show us what you did. – pfnuesel Apr 6 '16 at 16:15
  • I have updated and added my progress. – DynamicQ Apr 6 '16 at 16:38

Note: I had to put this together on a BSD system which might have a last output format different from yours. The output of last on my system looks like this:

guido     ttys000                   Wed Apr  6 18:44 - 18:44  (00:00)
guido     ttys000                   Wed Apr  6 14:36 - 14:55  (00:18)
guido     ttys000                   Wed Apr  6 13:56 - 14:33  (00:37)

Therefore, you'll probably need to change some of the field specifiers in the awk code below to match the output of last -a on your system.

That said, here's my approach which relies on awkonly to do the work:


last | awk '
    # Skip final 2 lines of output
    # (empty line followed by "wtmp begins..."
    /^$/ { exit }

    # Increment connections per user
    # Increment connections per user+ip combination
        # Possibly need to change $1 and $2 to other field numbers
        # depending on output of your "last"
        user[$1] ++;
        userip[$1,$2] ++;

    # For each user, print total and scan user+ip array
    # for user+ip totals accumulated for this user
    END {
        for (u in user) {
            print u " : " user[u];
            for (idx in userip) {
            split(idx, arr, SUBSEP);
            if (arr[1] == u) print "\t" arr[2] " - " userip[idx];

Example output:

root : 7
    console - 7
guido : 682
    console - 69
    ttys000 - 446
|improve this answer|||||
  • Hey, thank you so much, it works perfectly. Your approach is far better than mine. I'm new to this and I'm learning to do it on my own. You got any tips for me? – DynamicQ Apr 6 '16 at 19:55
  • @DynamicQ You're welcome. I find myself resorting to awk, sed, perl and bash most often when it comes to logfile processing, text+number crunching, and all kinds of data consolidation and cross-referencing. In my opinion, it really pays off to learn the complex features and advanced possibilities available with these tools. As a starting point, google for "sed advanced tutorial", "awk advanced examples" etc. to find lots of example-based info on these topics. – Guido Apr 6 '16 at 20:02

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.