I want to monitor the output of a command which keeps running infinitely and prints a line every now and then. It displays events of a hardware button and each line indicates a push.
My script is supposed to run other commands when it receives lines, but the problem is that not the content of those lines decide which command must be run, but the number of lines within a given delay.
In other words, the user may push this monitored button several times and different commands will be executed depending on how often the button is pressed. The user has 2 seconds time between two presses before the command will be picked based on the number of consecutive presses.
I currently have a Bash script with this structure:
#!/bin/bash lasttouch="0" MONITORING_COMMAND | while read line; do if [ $(date +%s --date="2 seconds ago") -lt $lasttouch ] then COMMAND2 else lasttouch=$(date +%s) COMMAND1 fi done
This however does only handle up to two consecutive presses and it executes COMMAND1
on every event, even if a subsequent press follows in time and COMMAND2
should run instead.
I actually have no idea how to implement this properly in Bash. I think I need some kind of multithreading, one thread listening for incoming lines and increasing a counter and another thread running a countdown of 2 seconds after every event and resetting the counter and executing the appropriate command once the countdown times out without additional events.
Advertisement
Answer
You can set a function for your single push waiting for the required time before executing COMMAND1
, record its pid with $!
and kill it when you actually receive a double push before the required time.
Here is an example with a delay of 700 milliseconds :
#!/bin/bash MONITORING_COMMAND="your monitoring command here" PUSH_NUM=1 #1 => until double push detection | 2 => until triple push detection etc... MAX_DELAY=700 #the delay in between push in milliseconds inc=0 remaining_delay=0 # wait_push <command value> <time left to sleep before taking the push> wait_push() { if [ ! -z "$2" ]; then sleep $2 fi inc=0 #switch between all your command here #COMMAND0 : normal push #COMMAND1 : double push #COMMAND2 : triple push etc.. echo "push is detected here: execute $1 here" pid="" lasttouch="" } $MONITORING_COMMAND | while read line ; do current=$(($(date +%s%N)/1000000)) if [ ! -z "$lasttouch" ]; then diff=`expr $current - $lasttouch` if test $diff -lt $MAX_DELAY then inc=$((inc+1)) if [ "$inc" -lt $PUSH_NUM ]; then if [ ! -z "$pid" ]; then kill $pid 2>/dev/null wait $pid 2>/dev/null fi remaining_delay=$((remaining_delay-diff)) time=`awk -v delay=$remaining_delay 'BEGIN { print (delay / 1000) }'` #normal push wait_push "COMMAND${inc}" $time & pid=$! continue elif [ "$inc" == $PUSH_NUM ]; then if [ ! -z "$pid" ]; then kill $pid 2>/dev/null wait $pid 2>/dev/null fi wait_push "COMMAND${inc}" continue fi else inc=0 fi fi if [ "$inc" == 0 ]; then remaining_delay=$MAX_DELAY time=`awk -v delay=$MAX_DELAY 'BEGIN { print (delay / 1000) }'` #normal push wait_push "COMMAND${inc}" $time & pid=$! fi lasttouch=$current done
You can increase the push number editing variable PUSH_NUM
:
- double push :
PUSH_NUM=1
- tripple push :
PUSH_NUM=2
- etc
You will have all command processing in wait_push
function. This takes into account time remaining between all consecutive push event (which dont exceed MAX_DELAY
ms)