Comando Block / prevent se tiver sido executado dentro dos últimos x segundos / minutos

3

(Apenas para conclusão: a história; você não precisa ler isto se você não quer saber porque eu estou fazendo esta pergunta : Eu tenho uma aplicação demoníaca na webcam (chamado de "movimento") com detecção de movimento da câmera.Este demônio é capaz de disparar um comando personalizado quando há um movimento detectado pela câmera.Eu também instalei um pequeno programa de linha de comando que facilmente pode enviar notificações push para o meu celular android. o cam-demon para executar esse comando push-message quando ele detecta um movimento.)

O problema: O demônio aciona esse comando personalizado com cada quadro que ele leva para um movimento, levando-me a uma enorme quantidade de notificações push quando há um movimento contínuo por apenas - digamos - 5 segundos (a taxa de quadros da câmera é definido para 10 fotos / segundo, então eu recebo 10 push-msgs a cada segundo que é considerado um movimento).

Eu preciso de um script ou programa que bloqueie o comando push-msg se já tiver sido executado nos últimos x segundos / minutos.

Eu posso imaginar algo como:

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

Não consegui encontrar uma maneira fácil / ainda elegante de resolver isso (sem gravar arquivos com carimbos de data e hora e verificar o conteúdo desses arquivos). Nem eu encontrei alguém com um problema semelhante.

Existe algum tipo de proxy de comando ou algo que possa resolver meu problema como descrito acima o mais fácil possível?

    
por serjoscha 07.10.2017 / 16:34

1 resposta

4

Armazenando o último horário de chamada como a hora da última modificação de um arquivo

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;

Para ser usado como:

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

Ele registra a hora da última execução como a hora da última modificação de /some/file e não executa o comando se a idade desse arquivo for menor que a hora especificada.

shell

Com o BSD ou o GNU find , você pode fazer isso com:

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

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

Para executar como:

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

Em qualquer caso, você terá que armazenar as informações sobre a última execução em algum lugar que persista para as próximas execuções. O sistema de arquivos é um lugar óbvio para isso. Essa é aquela em que você pode reservar alguma área para si mesmo.

processo de sono com nome específico

Outro namespace poderia ser, por exemplo, nomes de processos:

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

Para ser usado como:

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

(assumindo uma implementação de sleep que não se importa com o seu argv[0] ).

Estamos usando bash em vez de sh para seu exec -a arg0 . Se você não tiver bash , outros shells compatíveis são ksh93 , mksh , yash e zsh . Ou você pode reverter para perl novamente.

Observe que esse namespace não está reservado. Não há nada que impeça outro usuário de criar um processo com o mesmo nome (em vez de usar um arquivo ~/.lastrun na abordagem baseada em arquivo), no entanto, considerando que esses scripts são iniciados pelo mesmo processo motion , você poderia restringir a pesquisa por processo àqueles com o mesmo ID de processo pai:

Melhoria para quando todos os scripts são sempre iniciados pelo mesmo processo

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

Somente Linux: use uma chave do kernel com um tempo limite

No Linux, você também pode usar uma chave no chaveiro da sessão do usuário. Isso realmente não foi projetado para isso, mas aqui é útil, pois essas chaves persistem ao longo do tempo e podem receber um tempo limite:

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

Agora, isso não importa realmente no seu caso, pois você não está executando duas instâncias desse script ao mesmo tempo, mas todas elas têm condições de corrida, o que faz com que ele não garanta que duas instâncias ganhas pode ser executado dentro do tempo especificado. Se duas instâncias forem executadas ao mesmo tempo, elas podem verificar se a condição está correta antes de qualquer uma delas reconfigurá-la.

Bloquear um arquivo para evitar a condição de corrida

Uma abordagem que funcionaria em torno disso seria ter o processo sleep mantendo um bloqueio em um arquivo:

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

(além disso, ambos sleep e o comando sendo executado manterão o bloqueio, o que garantirá que duas instâncias do comando não sejam executadas ao mesmo tempo, mesmo que demorem mais tempo para serem executadas do que o comando sleep ) .

    
por 07.10.2017 / 17:22

Tags