It's already been pointed out that the delay caused by whatever's gathering your sensor data may be a flicker factor or might cause other display weirdness.
So here's an alternate take on this, in minimal form.
#!/usr/bin/env/ bash
# This generates random sensor data and stores it in predictably named temp files,
# after a short random delay.
function gather() {
while sleep $(( $RANDOM % 3 )); do
printf '%2d\n' $(( $RANDOM % 100 )) > /tmp/t.$$.$1
done
}
main() {
# Background our data gatherers...
gather i &
gather j &
# Print a couple of blank lines, since our format starts with "up"
printf '\n\n'
# and loop.
while sleep 1; do
# gather our randomly generated sensor data...
i=$( < /tmp/t.$$.i )
j=$( < /tmp/t.$$.j )
# and print it.
printf "$fmt" "$i" "$j"
done
}
cleol=$(tput el)
up2=$(tput cuu1; tput cuu1)
fmt="${up2}Measurement 1: %d${cleol}\nMeasurement 2: %d${cleol}\n"
main
Cursor movement is fun. :-)
But the point of all this is that the loop that is responsible for writing your output is VERY light-weight. It gets data from static text files, and it prints. Then repeats. All the heavy lifting is done in the backgrounded gather()
function, which updates the text files at a frequency that may be different from your display update frequency.
Note that as written, there's a race condition where your "read" might hit the file while the "write" is happening, but before data have been written. To minimize that, you could work around the race with something like this:
function gather() {
while sleep 1; do
value=$(
# This simulates the delay of a slow sensor read.
sleep $(( $RANDOM % 3 ))
printf '%2d\n' $(( $RANDOM % 100 ))
)
printf '%d\n' "$value" > /tmp/t.$$.$1
done
}
This is better, and may be "good enough", but writing to a temporary file like this is not an atomic filesystem operation, so the possibility of a race condition still exists.
In the following variation, we simulate a longish delay while data are read, but the output from the read command goes to a different temporary file, which get symlinked to upon a completion of the sensor read.
function gather() {
local n=0 item="${1//[^[:alnum:]]/}"
while :; do
old="$(readlink /tmp/t.$$.$item)"
(
# This simulates the delay of a slow sensor read.
sleep $(( $RANDOM % 3 ))
printf '%d\n' $(( $RANDOM % 100 ))
) > /tmp/t.$$.$item.$n
test -s /tmp/t.$$.$item.$n &&
ln -sfn /tmp/t.$$.$item.$n /tmp/t.$$.$item &&
test -f "$old" &&
rm -f "$old"
((n++))
sleep 1
done
}
Everything in the parentheses is what you'd run to generate your sensor output. And if you're afraid of running out of values for $n
(but not afraid of proton decay) you could switch to $RANDOM
instead of using the incrementing counter.
Have you thought of using an existing montoring system for whatever it is you're monitoring? It seems to me like problems like this have been solved already. :-)
UPDATE...
And just because I don't use my time well, here's an improved main()
function and the rest of the script:
function main() {
# Background our data gatherers...
local -a pids=()
for thing in "${things[@]}"; do
gather $thing &
pids+=($!); echo "Backgrounded $thing at $!"
done
trap "echo 'Quitting...'; kill $(printf '%s ' "${pids[@]}"); exit 0" 2
trap "echo 'Aborting...'; kill $(printf '%s ' "${pids[@]}"); exit 1" 1 3 15
# Wait for gatherers to have at least one round of data
sleep 2
# and loop.
local -A v=()
while sleep 1; do
# gather our randomly generated sensor data...
for thing in "${things[@]}"; do
v[$thing]=$( < /tmp/t.$$.$thing )
done
# and print it.
printf "$fmt" "${v[@]}"
done
}
things=( i j ) # the list of things to monitor
cleol=$(tput el) # you know what this is already
up2=$(tput cuu1; tput cuu1) # this too
fmt="${up2}Measurement 1: %d${cleol}\nMeasurement 2: %d${cleol}\n"
main
This puts your list of monitored items in a bash array, $things[]
, and backgrounds as required. It traps errors and breaks properly. The one thing it doesn't do is adapt your $fmt
to the size of the array. Or make coffee.