I want to run a command when the user becomes inactive (the system is idle). For example:

echo "You started to be inactive."

Also, when the user becomes active again (the system is not idle anymore):

echo "You started to be active, again."

I need a shell script that will do this. Is this possible without a timer/interval? Maybe some system events?

  • 2
    Can you go into a little bit deeper detail about what you actually want to achieve? – Nils Mar 22 '14 at 21:31
  • 3
    How do you measure idleness? Is a user watching a movie idle (because he isn't interacting with the computer)? Is a user who is logged in remotely active? – Gilles 'SO- stop being evil' Mar 22 '14 at 23:30
  • From what I know, the system has this built-in concept: idle, active etc. Is this right? – Ionică Bizău Mar 23 '14 at 5:33
  • @IonicăBizău: Not really. Idle in the context of the system would only mean that all processes are sleeping, that is 'waiting for something'. Although this may happen quite often on a modern system and may even be the case most of the time, it does not stay that way for long as there is always something to be done and if it is updating the clock. Idleness, especially in the context of your question, is more a function of the user than the system and even than it is usually linked to a specific session. – Adaephon Mar 25 '14 at 8:32
  • @Adaephon Ok. In my concept, a system is idle when the user doesn't do any action (mouse move, click, key press) at the computer for x minutes. The system becomes active when the user make the first action: clicks a mouse button, moves it, presses a key and so on. Is it possible to detect these idle*/*active states using a shell script? – Ionică Bizău Mar 25 '14 at 11:33

This thread on the ArchLinux forums contains a short C program that queries the xscreensaver for information how long the user has been idle, this seems to be quite close to your requirements:

#include <X11/extensions/scrnsaver.h>
#include <stdio.h>

int main(void) {
    Display *dpy = XOpenDisplay(NULL);

    if (!dpy) {

    XScreenSaverInfo *info = XScreenSaverAllocInfo();
    XScreenSaverQueryInfo(dpy, DefaultRootWindow(dpy), info);
    printf("%u\n", info->idle);


Save this as getIdle.c and compile with

gcc -o getIdle getIdle.c -lXss -lX11

to get an executable file getIdle. This program prints the "idle time" (user does not move/click with mouse, does not use keyboard) in milliseconds, so a bash script that builds upon this could looke like this:


idleAfter=3000     # consider idle after 3000 ms

while true; do
  echo $idleTimeMillis  # just for debug purposes.
  if [[ $idle = false && $idleTimeMillis -gt $idleAfter ]] ; then
    echo "start idle"   # or whatever command(s) you want to run...

  if [[ $idle = true && $idleTimeMillis -lt $idleAfter ]] ; then
    echo "end idle"     # same here.
  sleep 1      # polling interval


This still needs regular polling, but it does everything you need...

| improve this answer | |
  • Works as supposed! +1 – Ionică Bizău Apr 3 '14 at 12:28
  • You are worth of more points! – Ionică Bizău Apr 3 '14 at 12:35
  • 5
    You could save yourself compiling your own program and just use xprintidle, which is available in most distributions and does exactly the same thing. – Riot Jul 7 '16 at 20:36
  • Deserves a Github repo: github.com/ceremcem/on-idle – ceremcem May 5 at 23:24
  • This code sometimes works okay, sometimes doesn't. I'm using this code for a long long time and it behaves unpredictable. I still couldn't figure out what prevents the computer from identified as "idle". – ceremcem Aug 21 at 21:48

TMOUT in bash will terminate an interactive session after the set number of seconds. You may use that mechanism.

You migth capture the logout by setting an according trap (I did not test that), or by using the bash-logout-scripts (~/.bash_logout).

Here is a good superuser-answer into that direction.

| improve this answer | |
  • This does not address how the user would execute a command, rather than logging out, after $TMOUT seconds have passed. – chepner Mar 23 '14 at 3:46
  • Can you add more information to your answer? It is still unclear for me... – Ionică Bizău Mar 23 '14 at 6:39
  • @chepner I added some more detail to my answer. – Nils Mar 23 '14 at 21:53
  • Either way, this simply logs the user out after time is up. I don't think there is any way to abort the log out, either from an EXIT trap or from .bash_logout. – chepner Mar 24 '14 at 12:30

This is not quite what you asked for, but there is always the batch-command (usually a special invocation of the at-command and using the atd-daemon).

batch lets you cue-up a command to be run when the load-average drop below a certain limit (usually 1.5, but this can be set when starting atd). With at it's also possible to cue a job in such a way that rather than being run at a certain time; the job is just delivered to batchat that time, and first run when the load-average drops (eg. it's run as soon as the load-average drops under 1.5 sometime after 2:00am).

Unfortunately a batch-job will then run to it's end, it will not stop if the computer is no-longer idle.


If you have to go the programming-route (which it looks like from the other answers), I think I'd try to make something similar to the atd or crond daemons, that monitored logged-in users and/or load-average. This daemon could then run scripts/programs from a certain directory, and start/continue or stop them (with signals) as needed be.

| improve this answer | |
  • If you did this and used .lock files you could easily handle timing issues. – mikeserv Apr 5 '14 at 12:02

This thread has a couple of solutions based on detecting keyboard and mouse activity. I run xprintidle from a cron job which starts every few minutes. But as they point out xprintidle is unmaintained, so you may want to install the Perl module and use that instead:

$ cpanm X11::IdleTime
$ sleep 10; perl -MX11::IdleTime -le 'print GetIdleTime()'

I would use either solution by polling from cron, in a script which exits at the top if the UI hasn't been sufficiently idle. Of course the script would need an export DISPLAY=:0.0 in order to talk to X11.

Remember that your keyboard and mouse may be inactive when watching a movie, or running a CPU-heavy task.

| improve this answer | |

I don't know of a way to do this without polling some sort of system stats, like the other answers use a screensaver or bash idle timer, or running from .bash_logout, but here's an idea to check CPU usage.

This would still involve polling every n seconds, and if your CPU usage is under whatever amount you choose then you can script whatever you want to run. However, whatever you run could raise the CPU usage, but you could use nice on your "stuff" to not count it.

Here's a test script using top, but you could use mpstat instead, or check load averages instead?

while true
idle=$(top -bn2 | grep "Cpu(s)"|tail -n 1|sed "s/.*, *\([0-9.]*\)%* id.*/\1/")
echo "idle is $idle"
if [[ $idle > 90 ]]
    echo "idle above 90%"
    echo "Do stuff now"
    echo "idle below 90%"
    echo "Stop doing stuff now"
sleep 1

That's just a script I threw together to test out reading the idle from top. You could parse /proc/stat but I think it only shows total times, and you'd need to compare results over an interval. Top has it's own problem for me (linux mint 16), on the first run it seems to never change cpustats, as if it has to wait to parse /proc/stat itself, hence the top -bn2 but in theory top -bn1 should work.

| improve this answer | |
  • Ugh... really? Polling the CPU stats? – Rolf Mar 8 '18 at 15:06
  • By the way, you could also poll the w command which shows user idle time. -- By the way I'm not judging, it's just that for me, I want to detect idle to put the machine to sleep, to spare power, and polling goes against that. – Rolf Mar 8 '18 at 15:11
  • @Rolf Sounds pretty judging... since that comment really doesn't add much it should probably be removed, yes? Anyway, the other answers use idle time in a few different ways, but how can you detect idle without looking at / asking the system? – Xen2050 Mar 10 '18 at 0:52

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.