If you are running a recent Linux OS with SystemD, you can use the SystemD Timer unit to run your script at any granularity level you wish (theoretically down to nanoseconds), and - if you wish - much more flexible launching rules than Cron ever allowed. No sleep
kludges required
It takes a bit more to set up than a single line in a cron file, but if you need anything better than "Every minute", it is well worth the effort.
The SystemD timer model is basically this: timers are units that start service units when a timer elapses.
So for every script/command that you want to schedule, you must have a service unit and then an additional timer unit. A single timer unit can include multiple schedules, so you normally wouldn't need more than one timer and one service.
Here is a simple example that logs "Hello World" every 10 seconds:
(to create these files, you can use sudo tee path-to-file
and paste the file content then press CTRL+D, or use your text editor of choice)
/etc/systemd/system/helloworld.service
:
[Unit]
Description=Say Hello
[Service]
ExecStart=/usr/bin/logger -i Hello World
/etc/systemd/system/helloworld.timer
:
[Unit]
Description=Say Hello every 10 seconds
[Timer]
OnBootSec=10
OnUnitActiveSec=10
AccuracySec=1ms
[Install]
WantedBy=timers.target
After setting up these units (in /etc/systemd/system
, as described above, for a system-wide setting, or at ~/.config/systemd/user
for a user-specific setup), you need to enable the timer (not the service though) by running systemctl enable --now helloworld.timer
(the --now
flag also starts the timer immediately, otherwise, it will only start after the next boot, or user login).
The [Timer]
section fields used here are as follows:
OnBootSec
- start the service this many seconds after each boot.
OnUnitActiveSec
- start the service this many seconds after the last time the service was started. This is what causes the timer to repeat itself and behave like a cron job.
AccuracySec
- sets the accuracy of the timer. Timers are only as accurate as this field sets, and the default is 1 minute (emulates cron). The main reason to not demand the best accuracy is to improve power consumption - if SystemD can schedule the next run to coincide with other events, it needs to wake the CPU less often. The 1ms
in the example above is not ideal - I usually set accuracy to 1
(1 second) in my sub-minute scheduled jobs, but that would mean that if you look at the log showing the "Hello World" messages, you'd see that it is often late by 1 second. If you're OK with that, I suggest setting the accuracy to 1 second or more.
As you may have noticed, this timer doesn't mimic Cron all that well - in the sense that the command doesn't start at the beginning of every wall clock period (i.e. it doesn't start on the 10th second on the clock, then the 20th and so on). Instead is just happens when the timer ellapses. If the system booted at 12:05:37, then the next time the command runs will be at 12:05:47, then at 12:05:57, etc. If you are interested in actual wall clock accuracy, then you may want to replace the OnBootSec
and OnUnitActiveSec
fields and instead set an OnCalendar
rule with the schedule that you want (which as far as I understand can't be faster than 1 second, using the calendar format). The above example can also be written as:
OnCalendar=*-*-* *:*:00,10,20,30,40,50
Last note: as you probably guessed, the helloworld.timer
unit starts the helloworld.service
unit because they have the same name (minus the unit type suffix). This is the default, but you can override that by setting the Unit
field for the [Timer]
section.
More gory details can be found at: