Introduction
In this post I just want to show a short piece of code that can be useful when managing with Bash
processes that run while the system is up and have sleep/waiting times. Imagine the following situation: you have coded a service that is always running. This service should perform a certain operation every minute ending in X (0X, 1X, 2X, etc.). The operation running time is variable, but always smaller than the frequency at which it is triggered. An easy solution could be to sleep your service a fix quantity of minutes every time the operation is performed. However, seen that the operation running time is not fixed, the frequency will not be always the same.
Solution proposed
A more elaborated solution would be to calculate how many seconds should be slept until the next minute ended in X. So, for instance, if you want to run the process every minute ending in 4, you should do something like:
1 2 3 4 5 6 7 8 9 10 |
#/bin/bash minuteEnd=4 # will run when (currentMinute mod 10) = 4 while true do #yourOperationCode loopWaitTime=$(( (((60 * (10 - ($(date +%-M) % 10))) + ((( minuteEnd * 60 )) - $(date +%-S))) % 600 ) )) echo "Sleeping $loopWaitTime seconds"; sleep $loopWaitTime done |
This code will run once per 10 minutes, waking up in every minute ending in 4. The sleeping time is determined by calculating first the difference between current minute and desired minute. To the result it is subtracted the seconds to reach this minute. Over this results is applied modulus operation to obtain an sleeping time of, maximum, 10 minutes.
If the execution time of #yourOperationCode takes less than a second, I would recommend to force 1 second sleep before calculating the loopWaitTime
. By this way yo will avoid obtaining a sleep of 0 seconds, executing the same code more than one time per iteration.
If you want your script to run once per 5 minutes, use the following code. This will run in every minute ended in 4 or 9.
1 2 3 4 5 6 7 8 9 10 11 |
#/bin/bash minuteEnd=4 # will run when (currentMinute mod 5) = 4 (minutes x4 or x9) while true do #yourOperationCode loopWaitTime=$(( (((60 * (5- ($(date +%-M) % 5))) + ((( minuteEnd * 60 )) - $(date +%-S))) % 300) )) echo "Sleeping $loopWaitTime seconds"; sleep $loopWaitTime done |
Finally, if what you want is to run once per hour (when the minute ends in 04), use this script:
1 2 3 4 5 6 7 8 9 |
#/bin/bash minuteEnd=4 # will run when (currentMinute mod 60) = 04 while true do #yourOperationCode loopWaitTime=$(( (((60 * (60- ($(date +%-M) % 60))) + ((( minuteEnd * 60 )) - $(date +%-S))) % 6000) )) echo "Sleeping $loopWaitTime seconds"; sleep $loopWaitTime done |
2 thoughts on “Sleeping a process until next X minute”