GNU/Linux >> Tutoriels Linux >  >> Linux

Bloquer/empêcher la commande si elle a été exécutée au cours des X dernières secondes/minutes ?

(Juste pour compléter :l'histoire ; vous n'avez pas besoin de lire ceci si vous ne voulez pas savoir pourquoi je pose cette question :J'ai une application démon webcam (appelée "mouvement") avec détection de mouvement de la caméra. Ce démon est capable de déclencher une commande personnalisée lorsqu'un mouvement est détecté par la caméra. J'ai en outre installé un petit programme en ligne de commande qui peut facilement envoyer des notifications push à mon mobile Android. J'ai configuré le cam-demon pour qu'il exécute cette commande de message push lorsqu'il détecte un mouvement.)

Le problème :le démon déclenche cette commande personnalisée à chaque image qu'il prend pour un mouvement, ce qui me conduit à une quantité massive de notifications push lorsqu'il y a un mouvement continu pendant seulement - disons - 5 secondes (la fréquence d'images de la caméra est réglée sur 10 pics/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 cette commande push-msg si elle a déjà été exécutée au cours des x dernières 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 n'ai pas trouvé de moyen simple/mais élégant de résoudre ce problème (sans écrire de fichiers avec des horodatages, puis vérifier le contenu de ces fichiers). Je n'ai pas pu non plus trouver quelqu'un ayant un problème similaire.

Existe-t-il une sorte de proxy de commande ou quelque chose qui résoudrait mon problème comme décrit ci-dessus aussi facilement que possible ?

Réponse acceptée :

Stocker l'heure de la dernière invocation comme heure de la dernière modification d'un fichier

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;

A utiliser 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 l'heure de la dernière modification de /some/file et n'exécute pas la commande si l'âge de ce fichier est inférieur à l'heure spécifiée.

coque

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

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

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

Pour exécuter en tant que :

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 dans un endroit qui persiste pour les prochaines exécutions. Le système de fichiers est un endroit évident pour cela. C'est celui où vous pouvez réserver une zone pour vous-même.

processus de mise en veille avec un nom spécifique

Un autre espace de noms pourrait être par exemple les noms de processus :

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

A utiliser comme :

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

(en supposant un sleep implémentation 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 prenant en charge qui incluent ksh93 , mksh , yash et zsh . Ou vous pouvez revenir à perl à nouveau.

En relation :Activer le module Active Directory pour PowerShell via la ligne de commande ?

Notez que cet espace de noms n'est pas réservé. Rien n'empêche un autre utilisateur de créer un processus avec le même nom (par opposition à l'utilisation d'un ~/.lastrun file dans l'approche basée sur les fichiers), cependant étant donné qu'ici ces scripts sont tous démarrés par le même motion processus, vous pouvez restreindre la recherche de processus à ceux qui ont le même identifiant de processus parent :

Amélioration lorsque tous les scripts sont toujours lancés par le même processus

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

Linux uniquement :utilisez une clé de noyau avec un délai d'attente

Sous Linux, vous pouvez également utiliser une clé sur le trousseau de clés de session de l'utilisateur. Cela n'a pas vraiment été conçu pour cela, mais ici, c'est pratique car ces clés persistent dans le temps et peuvent avoir un délai d'expiration :

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

Maintenant, cela n'a pas vraiment d'importance dans votre cas car vous n'exécutez pas deux instances de ce script en même temps, mais toutes ont des conditions de concurrence qui font qu'il ne garantit pas que deux instances ne seront pas exécuté dans le temps imparti. Si deux instances sont exécutées en même temps, elles peuvent toutes deux vérifier que la condition est correcte avant que l'une d'elles ne la réinitialise.

Verrouiller un fichier pour éviter la condition de concurrence

Une approche qui contournerait cela serait d'avoir le sleep processus détient un verrou sur un fichier :

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

(en plus ici, les deux sleep et la commande en cours d'exécution maintiendrait le verrou, ce qui garantirait que deux instances de la commande ne s'exécutent pas en même temps, même si leur exécution prend plus de temps que le sleep commande).


Linux
  1. Astuce pour le terminal Linux :piratez la commande cd pour vous rappeler où vous avez été

  2. La commande "java" n'exécute pas la JVM qui a été installée

  3. Trouver les fichiers qui ont été modifiés au cours des dernières 24 heures

  4. Comment détecter si VT-X a été activé dans le BIOS ?

  5. Comment imprimer la dernière ligne d'un fichier compressé gz dans la ligne de commande ?

Comment savoir depuis combien de temps un processus s'exécute sous Linux

Tutoriel sur l'utilisation de la dernière commande dans le terminal Linux

Comment stocker le résultat d'une commande shell exécutée dans une variable en python ?

Qu'est-ce qui pourrait amener la commande file sous Linux à signaler un fichier texte en tant que données binaires ?

Signification des colonnes dans la dernière commande

Comment déterminer la meilleure taille d'octet pour la commande dd