I need two ways to terminate a part of my bash script.
Either a counter reaches a predefined number, or the user manually forces the script to continue with whatever the value the counter currently has.
Specifically - I'm listing USB drives. If there is 15 of them, the function that counts them exits and the script can continue.
My code looks a bit like this:
scannew(){
NEW=0
OLD=$NEW
while [ true ]; do
# count the new drives
lsblk -r > drives.new
diff drives.old drives.new | grep disk | cut -d' ' -f 2 | sort > drives.all
NEW=$(wc -l drives.all | cut -d' ' -f1)
echo -en " Detected drives: $NEW \r"
sleep 0.01
if [ "$NEW" -eq "15" ]; then # exit if we reach the limit
break
fi
done
}
# SOME CODE...
lsblk -r > drives.old
scannew & # start live device counter in the background
SCAN_PID=$! # remember it's PID
wait $SCAN_PID 2>/dev/null # wait until it dies
echo "It's on!"
# REST OF THE CODE...
I tried various stuff with the read
command, but the result is, the script will always wait for read to exit (after pressing ENTER) and I can't make the "15 limit" condition to override that.
For example I tried using read -t
instead of sleep
in the scannew()
function:
scannew(){
NEW=0
OLD=$NEW
while [ true ]; do
# count the new drives
lsblk -r > drives.new
diff drives.old drives.new | grep disk | cut -d' ' -f 2 | sort > drives.all
NEW=$(wc -l drives.all | cut -d' ' -f1)
echo -en " Detected drives: $NEW \r"
read -t 0.01 -n 1 && break # read instead of sleep
if [ "$NEW" -eq "15" ]; then
break
fi
done
}
However - it seems that the function subprocess doesn't have access to stdin, and using read -t 0.01 -n 1 < /dev/stdin && break
instead didn't work either.
How can I make this work?
read -t 0.01 -n 1 || break
: Don't you want to break on user input? But I thought read returns zero on receiving input, so you should use&&
instead.wait
ing for it immediately after anyway.read
but place it in the main script - once a key is pressed, you can send a signal to the background process, usingkill
. Withtrap
you can handle the signal any way you want (I'd recommend usingUSR1
orUSR2
). Sincescannew
does nothing more than scan the devices, yourtrap
can just doreturn 0
. AFAIK you can set up a trap from within a function so no worries there. Just make sure you define the trap at the start ofscannew
, just in case. Reading ilkkachu's message, I think you should check ifscannew
is actually doing something when it's taking time.