Выполните команду, если Linux не используется в течение 5 минут

Я хотел бы выполнить такую ​​команду, как

 notify-send 'a'

если моя Linux машина простаивала 5 минут.

В режиме ожидания я имею в виду то же самое, что экранная заставка, которая активируется, использовалась бы для определения "ожидания".

5 ответов

Я использую программу под названием xprintidle чтобы выяснить время простоя X, который, я сильно полагаю, использует тот же источник данных, что и заставки. xprintidle кажется, на самом деле больше нет апстрима, но пакет Debian жив и здоров.

Это очень простое приложение: оно возвращает количество миллисекунд с момента последнего взаимодействия X:

$ sleep 1 && xprintidle
940
$ sleep 5 && xprintidle
4916
$ sleep 10 && xprintidle
9932

(примечание: из-за базовой системы она будет постоянно давать значение в мс, немного меньшее, чем "фактическое" время простоя).

Вы можете использовать это, чтобы создать скрипт, который запускает определенную последовательность после пяти минут простоя, например:

#!/bin/sh

# Wanted trigger timeout in milliseconds.
IDLE_TIME=$((5*60*1000))

# Sequence to execute when timeout triggers.
trigger_cmd() {
    echo "Triggered action $(date)"
}

sleep_time=$IDLE_TIME
triggered=false

# ceil() instead of floor()
while sleep $(((sleep_time+999)/1000)); do
    idle=$(xprintidle)
    if [ $idle -ge $IDLE_TIME ]; then
        if ! $triggered; then
            trigger_cmd
            triggered=true
            sleep_time=$IDLE_TIME
        fi
    else
        triggered=false
        # Give 100 ms buffer to avoid frantic loops shortly before triggers.
        sleep_time=$((IDLE_TIME-idle+100))
    fi
done

Смещение в 100 мс происходит из-за ранее отмеченной ошибки xprintidle всегда будет возвращать время, немного меньшее, чем "фактическое" время простоя, когда выполняется так. Он будет работать без этого смещения, а затем будет более точным с точностью до одной десятой секунды, но это вызовет xprintidle проверять неистово в течение последних миллисекунд до окончания интервала. Ни в коем случае не свинья, но я бы посчитал это неуместным.

Я использовал подобный подход в скрипте Perl (плагин irssi) в течение достаточно долгого времени, но вышеописанное было только что написано и не было проверено, за исключением нескольких пробных прогонов во время написания.

Попробуйте, запустив его в терминале в X. Я рекомендую установить время ожидания, например, 5000 мс для тестирования, и добавить set -x прямо под #!/bin/sh чтобы получить информативный вывод, чтобы увидеть, как это работает.

Я использую xssstate для таких целей. Это доступно в suckless-tools пакет в Debian или Ubuntu, или апстрим.

Затем вы можете использовать следующий скрипт:

#!/bin/sh

if [ $# -lt 2 ];
then
    printf "usage: %s minutes command\n" "$(basename $0)" 2>&1
    exit 1
fi

timeout=$(($1*60*1000))
shift
cmd="$@"
triggered=false

while true
do
    tosleep=$(((timeout - $(xssstate -i)) / 1000))
    if [ $tosleep -le 0 ];
    then
        $triggered || $cmd
        triggered=true
    else
        triggered=false
        sleep $tosleep
    fi
done

Если вы используете GNOME Shell, вы можете запросить неактивность пользовательского сеанса из его диспетчера отображения Mutter, используяgdbus, нет необходимости в каких-либо сторонних утилитах.

Например:

      # polling interval in seconds
polling_interval=10

# timeout in milliseconds
timeout=300000

while true; do

  inactivity=`gdbus call --session \
             --dest org.gnome.Shell \
             --object-path /org/gnome/Mutter/IdleMonitor/Core \
             --method org.gnome.Mutter.IdleMonitor.GetIdletime \
             | grep -oP '^(\(uint64\s*)\K\d+'`

  if [[ $timeout -lt $inactivity ]] ; then
    notify-send 'a'
  fi

  sleep $polling_interval
  
done

Вот приложение C, которое я нашел и которое вы можете скомпилировать.

$ more xidle.c 
#include <stdio.h>
#include <X11/Xlib.h>
#include <X11/extensions/scrnsaver.h>

/* Report amount of X server idle time. */
/* Build with- */
/* cc xidle.c -o xidle -lX11 -lXext -lXss */


int main(int argc, char *argv[])
{
    Display *display;
    int event_base, error_base;
    XScreenSaverInfo info;
    float seconds;

    display = XOpenDisplay("");

    if (XScreenSaverQueryExtension(display, &event_base, &error_base)) {
    XScreenSaverQueryInfo(display, DefaultRootWindow(display), &info);

    seconds = (float)info.idle/1000.0f;
    printf("%f\n",seconds);
    return(0);
    }
    else {
    fprintf(stderr,"Error: XScreenSaver Extension not present\n");
    return(1);
    }
}

Для сборки требуется пара библиотек. В моей системе Fedora 19 мне нужны были следующие библиотеки:

$ rpm -qf /lib64/libX11.so.6 /lib64/libXext.so.6 /lib64/libXss.so.1
libX11-1.6.0-1.fc19.x86_64
libXext-1.3.2-1.fc19.x86_64
libXScrnSaver-1.2.2-5.fc19.x86_64

После того, как они были установлены, я скомпилировал вышеуказанное так:

$ gcc xidle.c -o xidle -lX11 -lXext -lXss

Вы можете видеть, что он может сообщить количество секунд, которое X определяет как простой, запустив его так:

$ while [ 1 ]; do ./xidle ; sleep 2;done
0.005000
1.948000
3.954000
5.959000
7.965000
0.073000   <--- moved the mouse here which resets it
0.035000

Используя этот исполняемый файл, вы можете собрать скрипт, который может сделать что-то вроде этого, отслеживая время простоя, сообщаемое xidle,

$ while [ 1 ]; do idle=$(./xidle); 
    [ $( echo "$idle > 5" | bc ) -eq 0 ] && echo "still < 5" || echo "now > 5"; 
    sleep 2;
done
still < 5
still < 5
still < 5
now > 5
now > 5
still < 5
still < 5
still < 5

Выше показывает still < 5 до 5 секунд простоя, когда он начинает говорить now > 5, что означает, что прошло более 5 секунд.

ПРИМЕЧАНИЕ: вы можете включить свой notify-send 'a' в приведенный выше пример.

Рекомендации

bsd ports (сбор пакетов) имеет программу, которая может сделать это:
http://man.openbsd.org/OpenBSD-current/man1/xidle.1
это доступно, например, здесь:
http://distcache.freebsd.org/local-distfiles/novel/xidle-26052015.tar.bz2

построить как:

 # apt-get install libxss-dev # for include/X11/extensions/scrnsaver.h
 # gcc -o /usr/local/bin/xidle xidle.c -lX11 -lXss

обратите внимание, что -program должен содержать полный путь к двоичному файлу, так как он передается в execv().

$ xidle -timeout 120 -program "/usr/bin/xlock -mode pyro"  
Другие вопросы по тегам