Ejecute un comando cuando el sistema esté inactivo y cuando esté activo nuevamente

15

Quiero ejecutar un comando cuando el usuario se vuelve inactivo (el sistema está inactivo). Por ejemplo:

echo "You started to be inactive."

Además, cuando el usuario vuelve a estar activo (el sistema ya no está inactivo):

echo "You started to be active, again."

Necesito un script de shell que haga esto. ¿Es esto posible sin un temporizador / intervalo? Tal vez algunos eventos del sistema?

Ionică Bizău
fuente
2
¿Puedes entrar en detalles un poco más profundos sobre lo que realmente quieres lograr?
Nils
3
¿Cómo se mide la ociosidad? ¿Está un usuario viendo una película inactiva (porque no está interactuando con la computadora)? ¿Está activo un usuario que ha iniciado sesión de forma remota?
Gilles 'SO- deja de ser malvado'
Por lo que sé, el sistema tiene este concepto incorporado: inactivo , activo , etc. ¿Es correcto?
Ionică Bizău
@ IonicăBizău: En realidad no. Inactivo en el contexto del sistema solo significaría que todos los procesos están inactivos , es decir, 'esperando algo'. Aunque esto puede ocurrir con bastante frecuencia en un sistema moderno e incluso puede ser el caso la mayor parte del tiempo, no se mantiene así por mucho tiempo, ya que siempre hay algo que hacer y si está actualizando el reloj. La inactividad , especialmente en el contexto de su pregunta, es más una función del usuario que del sistema e incluso de lo que generalmente está vinculado a una sesión específica.
Adaephon
@Adaephon Ok. En mi concepto, un sistema está inactivo cuando el usuario no realiza ninguna acción (mover el mouse, hacer clic, presionar una tecla) en la computadora durante x minutos. El sistema se activa cuando el usuario realiza la primera acción: hace clic en un botón del mouse, lo mueve, presiona una tecla, etc. ¿Es posible detectar estos estados inactivos * / * activos utilizando un script de shell?
Ionică Bizău

Respuestas:

17

Este hilo en los foros de ArchLinux contiene un breve programa en C que consulta el xscreensaver para obtener información sobre cuánto tiempo ha estado inactivo el usuario, esto parece estar bastante cerca de sus requisitos:

#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);
}

Guarda esto como getIdle.cy compila con

gcc -o getIdle getIdle.c -lXss -lX11

para obtener un archivo ejecutable getIdle. Este programa imprime el "tiempo de inactividad" (el usuario no se mueve / hace clic con el mouse, no usa el teclado) en milisegundos, por lo que un script bash que se basa en esto podría verse así:

#!/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

Esto todavía necesita un sondeo regular, pero hace todo lo que necesita ...

Jaspe
fuente
Funciona como se supone! +1
Ionică Bizău
¡Vale más puntos!
Ionică Bizău
2
Podría ahorrarse compilando su propio programa y simplemente usarlo xprintidle, que está disponible en la mayoría de las distribuciones y hace exactamente lo mismo.
Riot
3

TMOUT en bash finalizará una sesión interactiva después del número de segundos establecido. Puedes usar ese mecanismo.

Usted migth captura el cierre de sesión configurando una trampa correspondiente (no lo probé), o utilizando los scripts bash-logout (~ / .bash_logout).

Aquí hay una buena respuesta de superusuario en esa dirección.

Nils
fuente
Esto no aborda cómo el usuario ejecutaría un comando, en lugar de cerrar sesión, después de que $TMOUThayan pasado segundos.
chepner
¿Puedes agregar más información a tu respuesta? Todavía no está claro para mí ...
Ionică Bizău
@chepner Agregué más detalles a mi respuesta.
Nils
De cualquier manera, esto simplemente cierra la sesión del usuario una vez que se acaba el tiempo. No creo que haya alguna forma de cancelar el cierre de sesión, ya sea desde una EXITtrampa o desde .bash_logout.
chepner
3

Esto no es exactamente lo que solicitó, pero siempre existe el batchcomando-(generalmente una invocación especial del atcomando y el uso del atddemonio).

batchle permite ejecutar un comando para que se ejecute cuando el promedio de carga cae por debajo de un cierto límite (generalmente 1.5, pero esto se puede configurar al iniciar atd). Con attambién es posible indicar un trabajo de tal manera que en lugar de ejecutarse en un momento determinado; el trabajo se acaba de entregar batchen ese momento y se ejecuta primero cuando el promedio de carga cae (por ejemplo, se ejecuta tan pronto como el promedio de carga cae por debajo de 1.5 en algún momento después de las 2:00 a.m.).

Desafortunadamente, un trabajo por lotes se ejecutará hasta el final, no se detendrá si la computadora ya no está inactiva.

+++

Si tiene que ir a la ruta de programación (que parece de las otras respuestas), creo que trataría de hacer algo similar a los atdo cronddaemons, que monitoreó a los usuarios registrados y / o al promedio de carga. Este demonio podría ejecutar scripts / programas desde un determinado directorio y comenzar / continuar o detenerlos (con señales) según sea necesario.

Baard Kopperud
fuente
Si hiciste esto y usaste .lockarchivos, podrías manejar fácilmente los problemas de sincronización.
mikeserv
2

Este hilo tiene un par de soluciones basadas en la detección de la actividad del teclado y el mouse. Corro xprintidlede un trabajo cron que comienza cada pocos minutos. Pero, como señalan, xprintidleno se mantiene, por lo que es posible que desee instalar el módulo Perl y usarlo en su lugar:

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

Usaría cualquier solución sondeando desde cron, en un script que sale en la parte superior si la interfaz de usuario no ha estado lo suficientemente inactiva. Por supuesto, el script necesitaría un export DISPLAY=:0.0para poder hablar con X11.

Recuerde que su teclado y mouse pueden estar inactivos al mirar una película o al ejecutar una tarea con mucha CPU.

Metamórfico
fuente
1

No conozco una manera de hacer esto sin sondear algún tipo de estadísticas del sistema, como las otras respuestas usan un protector de pantalla o un temporizador inactivo bash, o se ejecutan desde .bash_logout, pero aquí hay una idea para verificar el uso de la CPU.

Esto aún implicaría sondear cada n segundos, y si el uso de su CPU está por debajo de la cantidad que elija, entonces puede escribir lo que quiera ejecutar. Sin embargo, lo que sea que ejecute podría aumentar el uso de la CPU, pero podría usar bien sus "cosas" para no contarlo.

Aquí hay un script de prueba que usa top, pero ¿podrías usar mpstat en su lugar o verificar los promedios de carga?

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

Ese es solo un guión que elaboré para probar leer el inactivo desde arriba. Podría analizar, /proc/statpero creo que solo muestra los tiempos totales, y necesitaría comparar los resultados en un intervalo. Top tiene su propio problema para mí (Linux mint 16), en la primera ejecución parece que nunca cambia los cpustats, como si tuviera que esperar para analizar / proc / stat en sí mismo, por lo tanto, top -bn2pero en teoría top -bn1debería funcionar.

Xen2050
fuente
Ugh ... en serio? ¿Sondeo de las estadísticas de la CPU?
Rolf
Por cierto, también puede sondear el wcomando que muestra el tiempo de inactividad del usuario. - Por cierto, no estoy juzgando, es solo eso para mí, quiero detectar inactivo para poner la máquina en reposo, ahorrar energía, y las encuestas van en contra de eso.
Rolf
@Rolf Suena bastante a juzgar ... ya que ese comentario realmente no agrega mucho, probablemente debería eliminarse, ¿sí? De todos modos, las otras respuestas usan el tiempo de inactividad de diferentes maneras, pero ¿cómo puede detectarlo sin mirar / preguntar al sistema?
Xen2050