Understanding Linux ‘w’ Command IDLE Column: Parsing Formats for Session Monitoring


2 views

When building session monitoring tools on Linux systems, the w command provides essential information about user activity - particularly through its IDLE column. However, interpreting this data correctly requires understanding three distinct time formats:

22:29m  # Hours:Minutes format
46.00s  # Seconds format  
27:47   # Minutes:Seconds format

Let's examine each format with concrete examples:

# Seconds format (XX.XXs)
12.34s = 12 seconds and 34 hundredths
# Hours:Minutes format (XX:XXm)
3:22m = 3 hours and 22 minutes
# Minutes:Seconds format (XX:XX)
45:30 = 45 minutes and 30 seconds

Here's a Python script to parse all three formats and alert when idle time exceeds a threshold:

import subprocess
import re
from datetime import timedelta

def parse_idle_time(idle_str):
    # Handle seconds format (XX.XXs)
    if idle_str.endswith('s'):
        return float(idle_str[:-1])
    
    # Handle hours:minutes format (XX:XXm)
    if idle_str.endswith('m'):
        h, m = map(int, idle_str[:-1].split(':'))
        return h * 3600 + m * 60
    
    # Handle minutes:seconds format (XX:XX)
    if ':' in idle_str:
        m, s = map(int, idle_str.split(':'))
        return m * 60 + s
    
    return 0

def check_idle_sessions(threshold_minutes=30):
    output = subprocess.check_output(['w', '-h']).decode()
    threshold = threshold_minutes * 60
    
    for line in output.splitlines()[1:]:
        parts = re.split(r'\s+', line.strip())
        user, tty, idle = parts[0], parts[1], parts[4]
        
        idle_seconds = parse_idle_time(idle)
        if idle_seconds > threshold:
            print(f"Alert: {user} on {tty} idle for {idle} ({idle_seconds} seconds)")

check_idle_sessions()

Be aware of these special cases in the IDLE field:

  • . indicates the user was active within the last minute
  • old means the session has been idle for over 24 hours
  • Empty value typically means the session is the current one

For more precise tracking, consider these alternatives to the w command:

# Using last command to check login history
last -a

# Using who command with idle time
who -u

# Checking terminal activity directly
ls -lu /dev/pts/*

The Linux w command displays user sessions with three distinct IDLE time formats:

1. 46.00s  - Seconds with decimal fractions (46 seconds)
2. 22:29m  - Hours:Minutes format (22 hours 29 minutes)
3. 27:47   - Pure colon-separated value (27 minutes 47 seconds)

Here's how each format should be interpreted programmatically:

import re
from datetime import timedelta

def parse_idle_time(idle_str):
    # Case 1: Seconds format (XX.YYs)
    if re.match(r'^\d+\.\d{2}s$', idle_str):
        return timedelta(seconds=float(idle_str[:-1]))
    
    # Case 2: Hours:Minutes format (XX:XXm)
    if re.match(r'^\d+:\d{2}m$', idle_str):
        hours, minutes = map(int, idle_str[:-1].split(':'))
        return timedelta(hours=hours, minutes=minutes)
    
    # Case 3: Pure colon format (XX:XX)
    if ':' in idle_str:
        parts = idle_str.split(':')
        if len(parts[0]) > 2:  # Handle days format if present
            days = int(parts[0])
            return timedelta(days=days, hours=int(parts[1]), minutes=int(parts[2]))
        return timedelta(minutes=int(parts[0]), seconds=int(parts[1]))
    
    return timedelta(0)  # Default case

Here's a complete Python implementation for session monitoring:

#!/usr/bin/env python3
import subprocess
import re
from datetime import datetime, timedelta

def get_sessions():
    result = subprocess.run(['w', '-hi'], 
                          stdout=subprocess.PIPE,
                          universal_newlines=True)
    return result.stdout.splitlines()

def alert_long_idle_users(max_idle=timedelta(minutes=30)):
    for line in get_sessions():
        parts = line.split()
        if len(parts) < 6:
            continue
            
        user, tty, idle = parts[0], parts[1], parts[4]
        idle_time = parse_idle_time(idle)
        
        if idle_time > max_idle:
            message = f"User {user} on {tty} idle for {str(idle_time)}"
            send_alert(message)

def send_alert(message):
    # Implement your notification logic here
    print(f"ALERT: {message}")
    # Example: subprocess.run(['notify-send', message])
  • The pure colon format (27:47) represents minutes:seconds when total time < 24 hours
  • For sessions over 24 hours idle, the format changes to days+hours:minutes (e.g., 3+12:30)
  • TTY console sessions show idle time differently than pts/x terminal sessions
  • The w command gets its data from /proc and utmp

For more precise tracking, consider these methods:

# Method 1: Check last activity time
last_activity = os.path.getatime(f"/dev/{tty}")

# Method 2: Use 'last' command
subprocess.run(['last', '-w', '-i'])

# Method 3: Parse utmp directly
import utmp
with open('/var/run/utmp', 'rb') as f:
    buf = f.read()
for entry in utmp.read(buf):
    print(entry)

When implementing session monitoring:

  • Batch process checks instead of continuous polling
  • Cache results for non-interactive users
  • Consider system load when running frequent checks
  • Use efficient string parsing (like re.compile for patterns)