3

I want to find out how many users logged in each day to my server in the current month. Starting from the first day of the month. Preferably I would like to use awk to do this.
My output should look something like this:

Apr 1: numOfLogins
Apr 2: numOfLogins
...
current day: numOfLogins
Chris Davies
  • 116,213
  • 16
  • 160
  • 287
Paralyz3d
  • 147

3 Answers3

3

You can use it like below :

last <user>  | awk -v dt="$(date +%b)" '$5==dt{ k[$5$6]+=1; a[$5$6]=$5"-"$6"-"$7  } END { for ( i in k ) { split(a[i],s,"-");print s[1]" "s[2]": "k[i]" No of Logins"  } }' | sort -n -k2

For non-specific to user:

last | grep -ve reboot -ve wtmp | awk -v dt="$(date +%b)" '$5==dt{ k[$5$6]+=1; a[$5$6]=$5"-"$6"-"$7  } END { for ( i in k ) { split(a[i],s,"-");print s[1]" "s[2]": "k[i]" No of Logins"  } }' | sort -n -k2

OR

List by users:

last | grep -ve reboot -ve wtmp | awk -v dt="$(date +%b)" '$5==dt{ k[$1$5$6]+=1; a[$1$5$6]=$1"-"$5"-"$6"-"$7  } END { for ( i in k ) { split(a[i],s,"-");print s[1]" "s[2]" "s[3]": "k[i]" No of Logins"  } }' | sort -n -k3
2

If your last supports the --since option, you can limit to the current month with:

last --since "$(date +'%Y-%m-01')"

The command date +'%Y-%m-01' prints the date of the first day of this month. For example, if I run it today, April 26th, 2020, I get:

$ date +'%Y-%m-01'
2020-04-01

So the last command becomes last --since 2020-04-01.

This means that all we need to do in awk is exclude the lines starting with reboot, the one starting with wmtp, and any empty ones and then count:

last --since "$(date +'%Y-%m-01')" | awk '!/^reboot/&&!/^wtmp /&&/./{date=$5" "$6; a[date]++}END{for(date in a){printf "%s: %d\n",date,a[date]}}' | sort -nk2

Or, a little easier to read:

last --since "$(date +'%Y-%m-01')" | 
    awk '!/^reboot/ && !/^wtmp / && /./{
        date=$5" "$6; 
        a[date]++
       }
       END{
        for(date in a){
            printf "%s: %d\n",date,a[date]
        }
       }' | sort -nk2

On my laptop, this returns:

$ last --since "$(date +'%Y-%m-01')" | awk '!/^reboot/&&!/^wtmp / && /./{date=$5" "$6; a[date]++}END{for(date in a){printf "%s: %d\n",date,a[date]}}' | sort -nk2
Apr 3: 1
Apr 5: 1
Apr 20: 1

If this is something you will be using often, you can make it into a shell function by adding these lines to your ~/.bashrc (or equivalent if you are not using bash):

monthLogins(){
    last --since "$(date +'%Y-%m-01')" | 
        awk '!/^reboot/ && !/^wtmp / && /./{
            date=$5" "$6; 
            a[date]++
           }
           END{
            for(date in a){
                printf "%s: %d\n",date,a[date]
            }
           }' | sort -nk2
}

You can then run monthLogins and get your desired output.

Alternatively, instead of filtering out reboot and wtmp, you could filter for only existing user names with (assuming your shell supports the <() construct):

monthLogins(){
    last --since "$(date +'%Y-%m-01')" | 
     grep -f <(cut -d: -f1 /etc/passwd)
        awk '/./{
            date=$5" "$6; 
            a[date]++
           }
           END{
            for(date in a){
                printf "%s: %d\n",date,a[date]
            }
           }' | sort -nk2
}
terdon
  • 242,166
  • In this answer some words other than reboot are present in the last output (runlevel, shutdown). My plan was to get all usernames from /etc/passwd, then to exclude all lines, which are not them. By this way we protect yourselves from an unknown word occurrence. – MiniMax Apr 26 '20 at 18:24
  • @MiniMax fair enough. I added a version that does that. – terdon Apr 26 '20 at 18:34
0

Many many thanks for Stalin Vignesh Kumar's answer. This code will display only the current month as determined by the system's month (date +%b), filter out the reboot user, which shows in the last command's output whenever a system is booted, and display all user's logins. I'll update my answer if I can figure out how to add leading zeroes to the output in the appropriate variables:

#!/bin/bash
last | grep `date +%b` | grep -v -e "reboot" | awk ' { k[$5$6]+=1; a[$5$6]=$5"-"$6"-"$7  } END { for ( i in k ) { split(a[i]"\n",s,"-");print s[1]" "s[2]": "k[i]" logins"  } }' | sort -n -k2