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).