当系统空闲时再次运行时运行命令


15

我想在用户变为非活动状态(系统处于空闲状态)时运行命令。例如:

echo "You started to be inactive."

同样,当用户再次活动时(系统不再处于空闲状态):

echo "You started to be active, again."

我需要一个可以执行此操作的shell脚本。没有计时器/间隔就可以吗?也许一些系统事件?


2
您能否更深入地了解您实际想要实现的目标?
尼尔斯

3
您如何衡量闲置程度?用户是否在看电影时处于空闲状态(因为他没有与计算机交互)?远程登录的用户是否活跃?
吉尔(Gilles)'所以

据我所知,系统具有内置的概念:空闲活动等。对吗?
尼卡比曹

@IonicăBizău:不是。在系统上下文中空闲只会意味着所有进程都在休眠,即“正在等待某事”。尽管这种情况在现代系统上可能经常发生,甚至在大多数情况下都可能发生,但是只要总有事情要做并且要更新时钟,它就不会一直保持下去。闲置,尤其是在您的问题中,闲置更多是用户的功能,而不是系统的功能,甚至比通常链接到特定会话的用户更多。
Adaephon 2014年

@Adaephon好的。在我的概念中,当用户在x分钟内未对计算机执行任何操作(鼠标移动,单击,按键)时,系统处于空闲状态。当用户执行第一个操作时,该系统将变为活动状态:单击鼠标按钮,移动鼠标按钮,按下键等。是否可以使用Shell脚本检测到这些空闲* / *活动状态?
尼卡比曹

Answers:


17

ArchLinux论坛上的该线程包含一个简短的C程序,该程序可查询xscreensaver以获取用户闲置多长时间的信息,这似乎非常符合您的要求:

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

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

    if (!dpy) {
        return(1);
    }

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

      return(0);
}

另存为getIdle.c并编译

gcc -o getIdle getIdle.c -lXss -lX11

获取可执行文件getIdle。此程序以毫秒为单位打印“空闲时间”(用户不使用鼠标移动/单击,不使用键盘),因此基于此的bash脚本可能如下所示:

#!/bin/bash

idle=false
idleAfter=3000     # consider idle after 3000 ms

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

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

done

这仍然需要定期轮询,但是它可以满足您的所有需求...


按预期工作!+1
尼卡比曹

您值得获得更多积分!
尼卡比曹

2
您可以省去编译自己的程序的麻烦,而只需使用xprintidle,大多数发行版中都提供,并且功能完全相同。
骚乱

3

在设置的秒数后,bash中的TMOUT将终止交互式会话。您可以使用该机制。

您可以通过设置相应的陷阱(我没有测试过)或使用bash-logout-scripts(〜/ .bash_logout)来捕获注销。

这是一个很好的超级用户答案。


这没有解决用户经过$TMOUT几秒钟后如何执行命令而不是注销的问题。
chepner 2014年

您可以在答案中添加更多信息吗?现在还不清楚我...
尼卡比曹

@chepner我在回答中添加了更多细节。
尼尔斯2014年

无论哪种方式,这都只是在时间用完后将用户注销。我认为没有任何方法可以从EXIT陷阱或从中止注销.bash_logout
chepner 2014年

3

这并不是您所要求的,但是总是有batch-command(通常是-command的特殊调用,at并使用atd-daemon)。

batch当负载平均下降到某个限制(通常为1.5,但可以在启动时设置atd)以下时,让您提示要运行的命令。有了at它也可以以这样的方式来提示一份工作,而不是在特定时间运行; 该作业仅batch在那时交付,并在平均负载下降时首先运行(例如,在凌晨2:00之后某个平均负载下降到1.5以下时,它将立即运行)。

不幸的是,批处理作业将一直运行到最后,如果计算机不再处于空闲状态,它也不会停止。

+++

如果您必须执行编程路线(从其他答案中可以看到),我想我会尝试制作类似于atdcrond守护程序的内容,以监视已登录的用户和/或负载平均。然后,该守护程序可以从某个目录运行脚本/程序,并根据需要启动/继续或停止它们(带有信号)。


如果您这样做并使用了.lock文件,则可以轻松解决计时问题。
mikeserv 2014年

2

线程具有基于检测键盘和鼠标活动的几种解决方案。我xprintidle从每隔几分钟开始的Cron作业开始。但是正如他们指出的那样,它xprintidle是不需要维护的,因此您可能需要安装Perl模块并使用它:

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

如果UI没有足够的空闲,我将使用从cron轮询的任何一种解决方案,该脚本会在顶部退出。当然,脚本需要使用export DISPLAY=:0.0才能与X11对话。

请记住,在观看电影或运行大量CPU任务时,键盘和鼠标可能处于非活动状态。


1

我不知道不轮询某种系统状态就可以做到这一点的方法,例如其他答案使用屏幕保护程序或bash空闲计时器,或从.bash_logout运行,但这是检查CPU使用率的一种方法。

这仍然涉及每n秒轮询一次,并且如果您的CPU使用率低于您选择的任何数量,那么您就可以编写要运行的脚本。但是,无论您执行任何操作都可能会增加CPU使用率,但是您可以在“东西”上使用nice来不计算它。

这是一个使用top的测试脚本,但是您可以使用mpstat代替,或者检查平均负载呢?

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

那只是我放在一起测试从顶部读取空闲状态的脚本。您可以解析,/proc/stat但我认为它只显示总时间,您需要比较一个时间间隔内的结果。Top对我来说是个问题(Linux mint 16),在第一次运行时,它似乎永远不会更改cpustats,好像它必须等待解析/ proc / stat本身一样,因此top -bn2理论上top -bn1应该可以。


gh ...真的吗?轮询CPU统计信息?
罗尔夫(Rolf)'18

顺便说一句,您还可以轮询w显示用户空闲时间的命令。-顺便说一下,对于我来说,我只是想检测闲置状态以使机器进入睡眠状态,以节省电源,而轮询与此相反。
罗尔夫(Rolf)'18年

@Rolf听起来很不错。。。因为该评论并没有增加太多,所以应该删除它,是吗?无论如何,其他答案以几种不同的方式使用空闲时间,但是如何在不查看/询问系统的情况下检测空闲?
Xen2050
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.