Uruchom polecenie, gdy system jest bezczynny i gdy jest ponownie aktywny

15

Chcę uruchomić polecenie, gdy użytkownik stanie się nieaktywny (system jest bezczynny). Na przykład:

echo "You started to be inactive."

Ponadto, gdy użytkownik ponownie stanie się aktywny (system nie jest już bezczynny):

echo "You started to be active, again."

Potrzebuję skryptu powłoki, który to zrobi. Czy to możliwe bez timera / interwału? Może jakieś zdarzenia systemowe?

Ionică Bizău
źródło
2
Czy możesz zagłębić się w bardziej szczegółowe informacje na temat tego, co naprawdę chcesz osiągnąć?
Nils,
3
Jak mierzysz lenistwo? Czy użytkownik ogląda film w stanie bezczynności (ponieważ nie wchodzi w interakcje z komputerem)? Czy użytkownik zalogowany zdalnie jest aktywny?
Gilles „SO- przestań być zły”
Z tego co wiem, system ma tę wbudowaną koncepcję: bezczynność , aktywność itp. Czy to prawda?
Ionică Bizău
@ IonicăBizău: Nie bardzo. Bezczynność w kontekście systemu oznaczałaby tylko, że wszystkie procesy śpią, czyli „czeka na coś”. Chociaż zdarza się to dość często w nowoczesnym systemie, a nawet przez większość czasu, nie pozostaje tak długo, ponieważ zawsze jest coś do zrobienia i jeśli aktualizuje się zegar. Bezczynność , szczególnie w kontekście twojego pytania, jest bardziej funkcją użytkownika niż systemu, a nawet jest zwykle związana z określoną sesją.
Adaephon
@Adaephon Ok. Według mojej koncepcji system jest bezczynny, gdy użytkownik nie wykonuje żadnych czynności (ruch myszy, kliknięcie, naciśnięcie klawisza) na komputerze przez x minut. System staje się aktywny, gdy użytkownik wykona pierwszą akcję: klika przycisk myszy, przesuwa go, naciska klawisz i tak dalej. Czy można wykryć te bezczynne * / * aktywne stany za pomocą skryptu powłoki?
Ionică Bizău

Odpowiedzi:

17

Wątek na forach ArchLinux zawiera krótki program C, który wysyła zapytanie do programu xscreensaver w celu uzyskania informacji o tym, jak długo użytkownik jest bezczynny.

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

Zapisz to jako getIdle.ci skompiluj z

gcc -o getIdle getIdle.c -lXss -lX11

aby uzyskać plik wykonywalny getIdle. Ten program wypisuje „czas bezczynności” (użytkownik nie porusza się / nie klika myszą, nie używa klawiatury) w milisekundach, więc skrypt bash oparty na tym może wyglądać następująco:

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

To wciąż wymaga regularnego odpytywania, ale robi wszystko, czego potrzebujesz ...

Jaspis
źródło
Działa jak należy! +1
Ionică Bizău
Jesteś wart więcej punktów!
Ionică Bizău
2
Możesz zaoszczędzić sobie kompilacji własnego programu i po prostu korzystać z niego xprintidle, który jest dostępny w większości dystrybucji i robi dokładnie to samo.
Riot
3

TMOUT w bash zakończy sesję interaktywną po ustalonej liczbie sekund. Możesz użyć tego mechanizmu.

Możesz przechwycić wylogowanie, ustawiając odpowiednią pułapkę (tego nie testowałem) lub używając skryptów bash-logout (~ / .bash_logout).

Oto dobra odpowiedź superużytkownika w tym kierunku.

Nils
źródło
Nie dotyczy to sposobu wykonywania polecenia przez użytkownika, zamiast wylogowania się po upływie $TMOUTkilku sekund.
chepner
Czy możesz dodać więcej informacji do swojej odpowiedzi? Dla mnie wciąż nie jest jasne ...
Ionică Bizău
@chepner Do mojej odpowiedzi dodałem więcej szczegółów.
Nils
Tak czy inaczej, po prostu wylogowuje użytkownika po upływie określonego czasu. Nie sądzę, że istnieje sposób na przerwanie wylogowania, z EXITpułapki lub z .bash_logout.
chepner
3

Nie jest to dokładnie to, o co prosiłeś, ale zawsze istnieje batchpolecenie (zwykle specjalne wywołanie atpolecenia i użycie -daemona atd).

batchpozwala podpowiedzieć komendę, która ma zostać uruchomiona, gdy średnia wartość obciążenia spadnie poniżej określonego limitu (zwykle 1,5, ale można to ustawić podczas uruchamiania atd). Dzięki attemu możliwe jest także wskazanie zadania w taki sposób, że zamiast być uruchamianym w określonym czasie; zadanie jest właśnie dostarczane batchw tym czasie i jest uruchamiane po raz pierwszy, gdy spada średnie obciążenie (np. jest uruchamiane, gdy średnia obciążenie spadnie poniżej 1,5 po 2:00 rano).

Niestety zadanie wsadowe zostanie następnie uruchomione do końca, nie zatrzyma się, jeśli komputer nie będzie już bezczynny.

+++

Jeśli musisz przejść ścieżkę programowania (która wygląda na inne odpowiedzi), myślę, że spróbowałbym stworzyć coś podobnego do demonów atdlub cronddemonów, które monitorowałyby zalogowanych użytkowników i / lub średnie obciążenie. Ten demon może następnie uruchamiać skrypty / programy z określonego katalogu i uruchamiać / kontynuować lub zatrzymać je (z sygnałami) w razie potrzeby.

Baard Kopperud
źródło
Jeśli to zrobiłeś i użyłeś .lockplików, możesz łatwo poradzić sobie z problemami z czasem.
mikeserv
2

Ten wątek ma kilka rozwiązań opartych na wykrywaniu aktywności klawiatury i myszy. Uciekam xprintidleod zadania crona, które zaczyna się co kilka minut. Ale, jak wskazują, xprintidlejest nieobsługiwany, więc możesz chcieć zainstalować moduł Perla i użyć go zamiast tego:

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

Skorzystałbym z obu rozwiązań poprzez odpytywanie z crona w skrypcie, który kończy się u góry, jeśli interfejs użytkownika nie był wystarczająco bezczynny. Oczywiście skrypt będzie potrzebował export DISPLAY=:0.0, aby rozmawiać z X11.

Pamiętaj, że klawiatura i mysz mogą być nieaktywne podczas oglądania filmu lub wykonywania zadań obciążających procesor.

Metamorficzny
źródło
1

Nie znam sposobu, aby to zrobić bez odpytywania statystyk systemu, jak inne odpowiedzi używają wygaszacza ekranu lub licznika czasu bezczynności bash lub uruchamiania z .bash_logout, ale oto pomysł, aby sprawdzić użycie procesora.

Wciąż wiązałoby się to z odpytywaniem co n sekund, a jeśli użycie procesora jest mniejsze niż wybrana ilość, możesz wykonać skrypt, co chcesz uruchomić. Jednak cokolwiek uruchomisz, może zwiększyć użycie procesora, ale możesz użyć ładnych „rzeczy”, aby go nie policzyć.

Oto skrypt testowy przy użyciu top, ale możesz zamiast tego użyć mpstat lub zamiast tego sprawdzić średnie obciążenia?

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

To tylko skrypt, który przygotowałem, aby przetestować czytanie bezczynności od góry. Możesz parsować, /proc/statale myślę, że pokazuje tylko całkowity czas i trzeba porównać wyniki w danym przedziale czasowym. Top ma dla mnie swój problem (linux mint 16), przy pierwszym uruchomieniu wydaje się, że nigdy nie zmienia cpustats, tak jakby musiał czekać na parsowanie / proc / stat, dlatego top -bn2teoretycznie top -bn1powinno działać.

Xen2050
źródło
Ugh ... naprawdę? Sondowanie statystyk procesora?
Rolf
Nawiasem mówiąc, możesz również sondować wpolecenie, które pokazuje czas bezczynności użytkownika. - Nawiasem mówiąc, nie oceniam, po prostu dla mnie chcę wykryć bezczynność, aby uśpić maszynę, oszczędzić energię, a odpytywanie jest temu przeciwne.
Rolf
@Rolf Brzmi nieźle oceniając ... ponieważ ten komentarz naprawdę nie dodaje wiele, prawdopodobnie powinien zostać usunięty, tak? W każdym razie inne odpowiedzi wykorzystują czas bezczynności na kilka różnych sposobów, ale jak można wykryć bezczynność bez patrzenia na system?
Xen2050,