I’m trying to write a bash script that polls btmon for device connections. I’ve got a working solution, but it’s absurdly slow, and it seems like the issue is grep being very slow to exit after finding a match (around 25 seconds). What can I do to either speed grep up or avoid using it altogether?
#!/bin/bash
COUNTER=0
while :
do
until btmon | grep -m 1 '@ Device Connected'
do :
done
let COUNTER=COUNTER+1
echo on 0 | cec-client RPI -s -d 1
sleep 5
echo as | cec-client RPI -s -d 1
until btmon | grep -m 1 '@ Device Disconnected'
do :
done
let COUNTER=COUNTER-1
if [ $COUNTER -eq 0 ];
then echo standby 0 | cec-client RPI -s -d 1;
fi
done
edit: To clarify, btmon and is a bluetooth monitoring tool that’s part of the Bluez suite, and cec-client is a utility that’s packaged with libCEC for issuing commands across the HDMI-CEC serial bus (amongst other things).
Answers:
Thank you for visiting the Q&A section on Magenaut. Please note that all the answers may not help you solve the issue immediately. So please treat them as advisements. If you found the post helpful (or not), leave a comment & I’ll get back to you as soon as possible.
Method 1
In:
cmd1 | cmd2
Most shells (the Bourne shell, (t)csh, as well as yash and some versions of AT&T ksh under some conditions being the notable exceptions) wait for both cmd1 and cmd2.
In bash, you’ll notice that
sleep 1 | uname
returns after one second.
In:
btmon | grep -m 1 '@ Device Disconnected'
grep will exit as soon as it has found one occurrence of the pattern, but bash will still wait for btmon.
btmon will typically die of a SIGPIPE the next time it writes to the pipe after grep has returned, but if it never writes anything again, it would never receive that signal.
You could replace #! /bin/bash with #! /bin/ksh93 as that’s a shell compatible with bash and one that only waits for the last component of a pipeline. Then in
btmon | grep -m 1 '@ Device Disconnected'
after grep returns, btmon would be left running in background and the shell would carry on with the rest of the script.
If you wanted to kill btmon as soon as grep returns, POSIXly, you could do something like:
sh -c 'echo "$$"; exec btmon' | ( read pid grep -m1 '@ Device Disconnected' || exit kill "$pid" 2> /dev/null true)
All methods was sourced from stackoverflow.com or stackexchange.com, is licensed under cc by-sa 2.5, cc by-sa 3.0 and cc by-sa 4.0