Bash – Running a loop precisely once per second

bashsleeptimestamps

I'm running this loop to check and print some things every second. However, because the calculations take maybe a few hundred milliseconds, the printed time sometimes skip a second.

Is there any way to write such a loop that I am guaranteed to get a printout every second? (Provided, of course, that the calculations in the loop take less than a second :))

while true; do
  TIME=$(date +%H:%M:%S)
  # some calculations which take a few hundred milliseconds
  FOO=...
  BAR=...
  printf '%s  %s  %s\n' $TIME $FOO $BAR
  sleep 1
done

Best Answer

To stay a bit closer to the original code, what I do is:

while true; do
  sleep 1 &
  ...your stuff here...
  wait # for sleep
done

This changes the semantics a little: if your stuff took less than a second, it will simply wait for the full second to pass. However, if your stuff takes longer than a second for any reason, it won't keep spawning even more subprocesses with never any end to it.

So your stuff never runs in parallel, and not in the background, so variables work as expected too.

Note that if you do start additional background tasks as well, you'll have to change the wait instruction to only wait for the sleep process specifically.

If you need it to be even more accurate, you'll probably just have to sync it to the system clock and sleep ms instead of full seconds.


How to sync to system clock? No idea really, stupid attempt:

Default:

while sleep 1
do
    date +%N
done

Output: 003511461 010510925 016081282 021643477 028504349 03... (keeps growing)

Synced:

 while sleep 0.$((1999999999 - 1$(date +%N)))
 do
     date +%N
 done

Output: 002648691 001098397 002514348 001293023 001679137 00... (stays same)

Related Question