web-dev-qa-db-ja.com

システムがアイドル状態で、再びアクティブになったときにコマンドを実行する

ユーザーが非アクティブ(システムがアイドル状態)になったときにコマンドを実行したい。例えば:

echo "You started to be inactive."

また、ユーザーが再びアクティブになったとき(システムはもうアイドル状態ではありません):

echo "You started to be active, again."

これを行うシェルスクリプトが必要です。これはタイマー/インターバルなしで可能ですか?たぶんいくつかのシステムイベント?

15
Ionică Bizău

ArchLinuxフォーラムのこのスレッド は、ユーザーがアイドル状態になっている時間をxscreensaverに照会する短いCプログラムを含みます。これは、要件に非常に近いようです。

#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

これにはまだ定期的なポーリングが必要ですが、必要なことはすべて実行されます...

18
Jasper

これはあなたが要求したものではありませんが、常にbatch- commandがあります(通常、at- commandの特別な呼び出しとatd- daemonの使用)。

batchを使用すると、負荷平均が特定の制限(通常は1.5ですが、atdの開始時に設定できます)を下回ったときに実行するコマンドをキューに入れることができます。 atを使用すると、特定の時間に実行されるのではなく、ジョブをキューに入れることもできます。ジョブはその時点でbatchに配信され、負荷平均が低下したときに最初に実行されます(たとえば、午前2時以降、負荷平均が1.5未満に低下するとすぐに実行されます)。

残念ながら、バッチジョブは最後まで実行され、コンピュータがアイドル状態でなくなっても停止しません。

+++

(他の回答からのように見える)プログラミングルートに行く必要がある場合、私はatdまたはcrondデーモンに似たものを作ろうと思います。ユーザーおよび/または負荷平均。このデーモンは、特定のディレクトリからスクリプト/プログラムを実行し、必要に応じてそれらを(シグナルで)開始/続行または停止できます。

3
Baard Kopperud

BashのTMOUTは、設定された秒数後にインタラクティブセッションを終了します。そのメカニズムを使用できます。

適切なトラップを設定するか(私はテストしませんでした)、またはbash-logout-scripts(〜/ .bash_logout)を使用して、ログアウトをキャプチャします。

ここにその方向への良いスーパーユーザーの答えがあります。

3
Nils

This スレッドには、キーボードとマウスのアクティビティの検出に基づくいくつかのソリューションがあります。数分おきに開始するcronジョブからxprintidleを実行します。しかし、彼らが指摘するように、xprintidleは保守されていないので、Perlモジュールをインストールして、代わりにそれを使用することができます。

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

私は、UIが十分にアイドル状態になっていない場合に上部で終了するスクリプトで、cronからポーリングすることでどちらのソリューションも使用します。もちろん、スクリプトにはexport DISPLAY=:0.0 X11と通信するため。

映画を見ているときや、CPUに負荷のかかるタスクを実行しているときは、キーボードとマウスが非アクティブになっている可能性があることに注意してください。

2
Metamorphic

他の回答でスクリーンセーバーや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しかし、合計時間しか表示されないと思います。ある間隔で結果を比較する必要があります。トップには私自身の問題があります(linux mint 16)。最初の実行では、cpustatsを変更しないようです。まるで/ proc/stat自体の解析を待つ必要があるかのように、したがってtop -bn2ですが、理論的にはtop -bn1は動作するはずです。

1
Xen2050