Bloquer / Empêcher la command si elle a été exécutée dans les dernières x secondes / minutes

(Juste pour l'achèvement: l'histoire, vous n'avez pas besoin de lire ceci si vous ne voulez pas savoir pourquoi je pose cette question : j'ai une demon-application webcam (appelée "mouvement") avec détection de mouvement de la camera. est capable de triggersr une command personnalisée quand il y a un mouvement détecté par la camera.J'ai en outre installé un petit programme de command line qui peut facilement envoyer des notifications push à mon mobile Android.J'ai configuré le cam-démon pour exécuter cette command push-message comme il détecte une motion.)

Le problème: Le démon triggers cette command personnalisée avec chaque image qu'il prend pour un mouvement, ce qui m'amène à une quantité massive de push-notification quand il y a un mouvement continu pour juste – disons – 5 secondes (le framerate de la camera est mis à 10 photos / seconde donc je reçois 10 push-msgs chaque seconde qui est considéré comme un mouvement).

J'ai besoin d'un script ou d'un programme qui bloque la command push-msg si elle a déjà été exécutée au cours des dernières x secondes / minutes.

Je pourrais imaginer quelque chose comme:

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

Je ne pouvais pas find un moyen simple et élégant pour résoudre ce problème (sans écrire des files avec des horodatages, puis vérifier le contenu de ces files). Ni je pourrais find quelqu'un ayant un problème similaire.

Y at-il une sorte de proxy de command ou quelque chose qui résoudrait mon problème comme décrit ci-dessus aussi facile que possible?

Stocker la dernière heure d'appel comme la dernière heure de modification d'un file

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; 

Pour être utilisé comme:

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

Il enregistre l'heure de la dernière exécution comme la dernière heure de modification de /some/file et n'exécute pas la command si l'âge de ce file est inférieur à l'heure spécifiée.

coquille

Avec BSD ou GNU find , vous pourriez le faire avec:

 #! /bin/sh - file=${1?} time=${2?} shift 2 [ "$(find -- "$file" -prune -newermt "$time ago")" ] && exit 3 touch -- "$file" exec "$@" 

Pour fonctionner comme:

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

Dans tous les cas, vous devrez stocker les informations sur la dernière exécution à un endroit qui persiste pour les prochaines exécutions. Le système de files est un endroit évident pour cela. C'est un endroit où vous pouvez réserver un espace pour vous-même.

process de sumil avec un nom spécifique

Un autre espace de noms peut être par exemple des noms de process:

 #! /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 "$@" 

Pour être utilisé comme:

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

(en supposant une implémentation de sleep qui ne se soucie pas de son argv[0] ).

Nous utilisons bash au lieu de sh pour son exec -a arg0 . Si vous n'avez pas bash , d'autres shells qui supportent ksh93 , mksh , yash et zsh . Ou vous pouvez revenir à perl nouveau.

Notez que cet espace de noms n'est pas réservé. Rien n'empêche un autre user de créer un process portant le même nom (par opposition à l'utilisation d'un file ~/.lastrun dans l'approche basée sur les files). Cependant, étant donné que ces scripts sont tous lancés par le même process, vous pouvez restreindre la search de process à ceux avec le même ID de process parent:

Amélioration pour quand tous les scripts sont toujours lancés par le même process

 #! /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 "$@" 

Linux uniquement: utilisez une key de kernel avec un timeout d'attente

Sous Linux, vous pouvez également utiliser une key dans le trousseau de session de l'user. Cela n'a pas vraiment été conçu pour cela, mais ici, il est utile que ces keys persistent à travers le time et peuvent être donnés un timeout d'attente:

 #! /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 "$@" 

Maintenant, cela n'a pas vraiment d'importance dans votre cas car vous n'utilisez pas deux instances de ce script en même time, mais toutes ont une condition de course qui fait que cela ne garantit pas que deux instances ne seront pas exécuter dans le timeout spécifié. Si deux instances sont exécutées en même time, elles peuvent toutes deux vérifier que la condition est correcte avant que l'une d'entre elles ne la réinitialise.

Verrouiller un file pour éviter la condition de course

Une approche qui fonctionnerait serait d'avoir le process de sleep maintenir un verrou sur un file:

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

(en plus ici, sleep et la command exécutée maintiendront le verrou qui s'assurerait que pas deux instances de la command ne s'exécutent en même time, même si elles prennent plus de time que la command sleep ).