user_dev
user_dev

Reputation: 1431

How to compare the user idle session in bash to a limit in minutes?

I am trying to come up with a bash script to check if a user idle time is more than 30 minutes then kill the session but I am not able to come up with the right filter.

who -u | cut -c 1-10,38-50 > /tmp/idle$$

for idleSession in `cat /tmp/idle$$ | awk '{print $3}'`
do

    if [ "$idleSession" -gt 30 ]; then
       echo  $idleSession
    fi
done

I have found suggestions with egrep but I don't understand that. I keep getting

user_test.sh: line 6: [: 14:25: integer expression expected

Update: I updated the code with the typo and I got everything printed and value is not getting compared to my limit of 30m

Upvotes: 0

Views: 920

Answers (1)

pjh
pjh

Reputation: 8134

This Shellshock-clean code prints details of sessions on the current machine that have been idle for more than 30 minutes:

#! /bin/bash -p

# Check if an idle time string output by 'who -u' represents a long idle time
# (more than 30 minutes)
function is_long_idle_time
{
    local -r idle_time=$1

    [[ $idle_time == old ]] && return 0
    [[ $idle_time == *:* ]] || return 1

    local -r hh=${idle_time%:*}
    local -r mm=${idle_time#*:}
    local -r idle_minutes=$((60*10#$hh + 10#$mm))

    (( idle_minutes > 30 )) && return 0 || return 1
}

who_output=$(LC_ALL=C who -u)

while read -r user tty _ _ _ idle_time pid _ ; do
    if is_long_idle_time "$idle_time" ; then
        printf 'user=%s, tty=%s, idle_time=%s, pid=%s\n' \
            "$user" "$tty" "$idle_time" "$pid"
    fi
done <<<"$who_output"

The code assumes that the output of LC_ALL=C who -H -u looks like:

NAME     LINE         TIME         IDLE          PID COMMENT
username pts/9        Apr 25 18:42 06:44        3366 (:0)
username pts/10       Apr 25 18:42  old         3366 (:0)
username pts/11       Apr 25 18:44   .          3366 (:0)
username pts/12       Apr 25 18:44 00:25        3366 (:0)
...

It may look different on your system, in which case the code might need to be modified.

  • The "idle" string output by who -u can take several different forms. See who (The Open Group Base Specifications Issue 7) for details. Processing it is not completely trivial and is done by a function, is_long_idle_time, to keep the main code simpler.
  • The function extracts the hours (hh (06)) and minutes (mm (44)) from idle strings like '06:44' and calculates a total number of idle minutes (idle_minutes (404)). The base qualifiers (10#) in the arithmetic expression are necessary to prevent strings '08' and '09' being treated as invalid octal numbers. See Value too great for base (error token is "08").
  • The format of the who -u output can (and does) differ according to the Locale. Running it with LC_ALL=C who -u ensures that it will generate the same output regardless of the user's environment. See Explain the effects of export LANG, LC_CTYPE, LC_ALL.
  • Within the main loop you get the username, terminal/line, idle time, and PID of all sessions that have been idle for more than 30 minutes. However, it may not be straightforward to use this information to kill idle sessions. On some systems, multiple sessions may be associated with the same PID. Even if you can reliably determine the PIDs of idle sessions, the idleness may be false. For instance, a session that is running a long-running program that has generated no terminal output (yet) will appear to be idle. Killing it might not be a smart thing to do though. Consider using TMOUT instead. See How can one time out a root shell after a certain period of time? (and note that it can be used for any user, not just root).

Upvotes: 1

Related Questions