(Just for completion: the story; you don't need to read this if you do not want to know why I am asking this question: I got a webcam demon-application (called "motion") with camera motion detection. This demon is able to trigger a custom command when there is a motion detected by the camera. I furthermore installed a tiny commandline program that easily can send push notifications to my android mobile. I configured the cam-demon to run that push-message-command as he detects a motion.)
The problem: The demon triggers that custom command with every frame he takes for a motion, leading me to a massive amount of push-notification when there is a continuous motion for just – lets say – 5 seconds (the camera framerate is set to 10 pics/second so I get 10 push-msgs every second that is considered a motion).
I need a script or program that block that push-msg command if it has been run in the past x seconds / minutes already.
I could imagine something like:
$ proxy_command.sh --block_time=10s --command==androidpush -msg "There was a motion in your flat!"
I could not find an easy/yet elegant way to solve this (without writing files with timestamps and then checking for that files content). Neither I could find someone having a similar problem.
Is there some kind of command proxy or something that would solve my problem like described above as easy as possible?
Best Answer
Storing the last invocation time as the last modification time of a file
perl
To be used like:
It records the time of last run as the last modification time of
/some/file
and doesn't run the command if the age of that file is less than the specified time.shell
With BSD or GNU
find
, you could do it with:To run as:
In any case, you'll have to store the information about the last run in some place that persists for the next runs. The file system is an obvious place for that. That's one where you can reserve some area for yourself.
sleep process with specific name
Another namespace could be for instance process names:
To be used as:
(assuming a
sleep
implementation that doesn't care about itsargv[0]
).We're using
bash
instead ofsh
for itsexec -a arg0
. If you don't havebash
, other shells that support that includeksh93
,mksh
,yash
andzsh
. Or you could revert toperl
again.Note that that namespace is not reserved. There's nothing preventing another user to create a process with that same name (as opposed to using a
~/.lastrun
file in the file-based approach), however given that here those scripts are all started by the samemotion
process, you could restrict the search for process to those with the same parent process id:Improvement for when all the scripts are always started by the same process
Linux-only: use a kernel key with a timeout
On Linux, your could also use a key on the user's session keyring. That has not really be designed for that, but here it comes handy as those keys persist across time and can be given a timeout:
Now, it doesn't really matter in your case as you're not running two instances of that script at the same time, but all of those have a race conditions which makes that it doesn't guarantee that two instances won't be run within the specified time. If two instances are run at the same time, they could both verify that the condition is OK before any one of them resets it.
Locking a file to avoid the race condition
An approach that would work around that would be to have the
sleep
process hold a lock on a file:(in addition here, both
sleep
and the command being run would hold the lock which would make sure not two instances of the command run at the same time even if they take longer to run than thesleep
command).