GNU/Linux >> LINUX-Kenntnisse >  >> Linux

Befehl blockieren/verhindern, wenn er innerhalb der letzten X Sekunden/Minuten ausgeführt wurde?

(Nur zur Vervollständigung:die Geschichte; Sie brauchen dies nicht zu lesen, wenn Sie nicht wissen wollen, warum ich diese Frage stelle :Ich habe eine Webcam-Dämon-Anwendung (namens „Bewegung“) mit Kamerabewegungserkennung. Dieser Dämon kann einen benutzerdefinierten Befehl auslösen, wenn die Kamera eine Bewegung erkennt. Außerdem habe ich ein winziges Kommandozeilenprogramm installiert, das ganz einfach Push-Benachrichtigungen an mein Android-Handy senden kann. Ich habe den Cam-Dämon so konfiguriert, dass er diesen Push-Message-Befehl ausführt, wenn er eine Bewegung erkennt.)

Das Problem:Der Dämon löst diesen benutzerdefinierten Befehl mit jedem Frame aus, den er für eine Bewegung aufnimmt, was mich zu einer massiven Menge an Push-Benachrichtigungen führt, wenn es eine kontinuierliche Bewegung für nur – sagen wir – 5 Sekunden gibt (die Kamera-Framerate ist auf 10 eingestellt Bilder/Sekunde, also bekomme ich jede Sekunde 10 Push-Nachrichten, die als Bewegung gewertet werden).

Ich brauche ein Skript oder Programm, das diesen Push-msg-Befehl blockiert, wenn er in den letzten x Sekunden / Minuten bereits ausgeführt wurde.

Ich könnte mir sowas vorstellen wie:

$ proxy_command.sh --block_time=10s --command==androidpush -msg "There was a motion in your flat!"

Ich konnte keinen einfachen/noch eleganten Weg finden, dies zu lösen (ohne Dateien mit Zeitstempeln zu schreiben und dann den Inhalt dieser Dateien zu überprüfen). Ich konnte auch niemanden finden, der ein ähnliches Problem hat.

Gibt es eine Art Befehlsproxy oder etwas, das mein oben beschriebenes Problem so einfach wie möglich lösen würde?

Akzeptierte Antwort:

Speichern der letzten Aufrufzeit als letzte Änderungszeit einer Datei

perl

#! /usr/bin/perl
# usage: cmd file seconds cmd args
$file = shift @ARGV;
$time = shift @ARGV;
$age = -M $file;
exit 3 if defined($age) && 86400 * $age < $time;
open $fh, ">>", $file ||
  die "Can't open $file: $!\n";
utime undef, undef, $fh;
exec @ARGV;

Zu verwenden wie:

that-script /some/file 10 androidpush -msg 'There was a motion in your flat!'

Es zeichnet die Zeit der letzten Ausführung als letzte Änderungszeit von /some/file auf und führt den Befehl nicht aus, wenn das Alter dieser Datei kleiner als die angegebene Zeit ist.

Schale

Mit BSD oder GNU find , könnten Sie es tun mit:

#! /bin/sh -
file=${1?} time=${2?}
shift 2

[ "$(find -- "$file" -prune -newermt "$time ago")" ] && exit 3
touch -- "$file"
exec "[email protected]"

Ausführen als:

that-script /some/file 10sec androidpush -msg 'There was a motion in your flat!'

In jedem Fall müssen Sie die Informationen über den letzten Lauf an einem Ort speichern, der für die nächsten Läufe bestehen bleibt. Das Dateisystem ist dafür ein naheliegender Ort. Dort können Sie einen Bereich für sich selbst reservieren.

Sleep-Prozess mit spezifischem Namen

Ein anderer Namespace könnte zum Beispiel Prozessnamen sein:

#! /bin/bash -
label=$0-$(logname)@${1?} time=${2?}
shift 2
pgrep -f "^$label" > /dev/null 2>&1 && exit 3
(exec -a "$label" sleep "$time") &
exec "[email protected]"

Zu verwenden als:

that-script motion 10 androidpush -msg 'There was a motion in your flat!'

(vorausgesetzt, ein sleep Implementierung, die sich nicht um ihr argv[0] kümmert ).

Wir verwenden bash statt sh für seine exec -a arg0 . Wenn Sie bash nicht haben , andere Shells, die das unterstützen, enthalten ksh93 , mksh , yash und zsh . Oder Sie könnten zu perl zurückkehren nochmal.

Verwandt:Aktivieren des Active Directory-Moduls für PowerShell über die Befehlszeile?

Beachten Sie, dass dieser Namespace nicht reserviert ist. Nichts hindert einen anderen Benutzer daran, einen Prozess mit demselben Namen zu erstellen (im Gegensatz zur Verwendung eines ~/.lastrun Datei im dateibasierten Ansatz), jedoch unter der Voraussetzung, dass diese Skripte hier alle durch dieselbe motion gestartet werden Prozesses, könnten Sie die Suche nach Prozessen auf diejenigen mit derselben übergeordneten Prozess-ID beschränken:

Verbesserung, wenn alle Skripte immer von demselben Prozess gestartet werden

#! /bin/bash -
label=$0-${1?} time=${2?}
shift 2
pgrep -P "$PPID" -f "^$label" > /dev/null 2>&1 && exit 3
(exec -a "$label" sleep "$time") &
exec "[email protected]"

Nur Linux:Verwenden Sie einen Kernelschlüssel mit einem Timeout

Unter Linux können Sie auch einen Schlüssel am Sitzungsschlüsselbund des Benutzers verwenden. Das ist nicht wirklich dafür ausgelegt, aber hier ist es praktisch, da diese Schlüssel über die Zeit bestehen bleiben und mit einem Timeout versehen werden können:

#! /bin/sh -
key=$0-${1?} time=${2?}
shift 2
keyctl search @us user "$key" > /dev/null 2>&1 && exit 3
key=$(keyctl add user "$key" x @us) || exit
keyctl timeout "$key" "$time" || exit
exec "[email protected]"

Nun, es spielt in Ihrem Fall keine Rolle, da Sie nicht zwei Instanzen dieses Skripts gleichzeitig ausführen, aber alle haben eine Race-Bedingung, die es nicht garantiert, dass zwei Instanzen nicht ausgeführt werden innerhalb der angegebenen Zeit laufen. Wenn zwei Instanzen gleichzeitig ausgeführt werden, können beide überprüfen, ob die Bedingung in Ordnung ist, bevor eine von ihnen sie zurücksetzt.

Sperren einer Datei, um die Race-Condition zu vermeiden

Ein Ansatz, der das umgehen würde, wäre das sleep Prozess hält eine Sperre für eine Datei:

#! /bin/sh -
file=${1?} time=${2?}
shift 2
{
  flock -n 3 || exit 3
  sleep "$time" 3>&3 &
  exec "[email protected]"
} 3<> "$file"

(Außerdem hier sleep und der ausgeführte Befehl würde die Sperre halten, die sicherstellen würde, dass nicht zwei Instanzen des Befehls gleichzeitig ausgeführt werden, selbst wenn ihre Ausführung länger dauert als der sleep Befehl).


Linux
  1. Linux – Wie kann ich die Befehlszeile der in den letzten 10 Sekunden ausgeführten Prozesse anzeigen?

  2. Wie greife ich auf das letzte Argument eines kommentierten Befehls zu?

  3. Der Befehl „java“ führt die installierte JVM nicht aus

  4. Wie speichere ich das Ergebnis eines ausgeführten Shell-Befehls in einer Variablen in Python?

  5. Wie kann ich feststellen, ob VT-X im BIOS aktiviert wurde?

So finden Sie heraus, wie lange ein Prozess unter Linux läuft

Linux-Terminal-Trick:Hacken Sie den cd-Befehl, um sich daran zu erinnern, wo Sie gewesen sind

Tutorial zur Verwendung des letzten Befehls im Linux-Terminal

Finden Sie die Dateien, die in den letzten 24 Stunden geändert wurden

Was könnte dazu führen, dass der Dateibefehl in Linux eine Textdatei als Binärdaten meldet?

Bedeutung der Spalten im letzten Befehl