2

I have in my crontab the following

15 */4 * * * ...

My original intent was that I would run ... every 4 hours from when the computer boots up. If I power on at 8 am, it would run at 8, 12, 16, 20, ...; if I power on at 9am it would run at 9, 13, 17, 21, ...

My observation is that crontab seems to divide the hour by 4 and if the remainder is 0 it executes.

Is there a way I can achieve the former rather than the latter?

chribonn
  • 291
  • 1
  • 3
  • 15

3 Answers3

6

This is something that might more easily be done on current Ubuntu systems using a systemd timer.

Following the monotonic timer example in the archlinux wiki:

  1. create a service unit file to run your command (/usr/local/bin/foo in this example) as a oneshot service

    [Unit]
    Description=do some stuff on schedule defined by foo.timer
    

    [Service] Type=oneshot ExecStart=/usr/local/bin/foo

  2. create a corresponding timer unit with the desired time specifications (0 seconds after boot, and then 4 hours after the service unit was last activated)

    [Unit]
    Description=Run foo on boot and every 4 hours thereafter
    

    [Timer] OnBootSec=0 OnUnitActiveSec=4h

    [Install] WantedBy=timers.target

  3. enable the timer

    sudo systemctl enable foo.timer
    

After reboot, you should be able to see the new timer along with its last and next activation times:

$ systemctl list-timers foo
NEXT                        LEFT          LAST                        PASSED      UNIT      ACTIVATES  
Thu 2023-01-12 19:37:39 EST 3h 58min left Thu 2023-01-12 15:37:39 EST 1min 5s ago foo.timer foo.service

1 timers listed. Pass --all to see loaded but inactive timers, too.

steeldriver
  • 136,215
  • 21
  • 243
  • 336
  • This addresses my needs. Would systemd retain a log as crontab (https://askubuntu.com/questions/56683/where-is-the-cron-crontab-log)? – chribonn Jan 13 '23 at 06:41
  • @chribonn the service invocations will get logged to the systemd journal - you can read them with something like journalctl -u foo or journalctl -xe -u foo etc. – steeldriver Jan 13 '23 at 11:57
3

The number after / is called a step value and it starts counting from hour 00 to hour 23 for hours ... So:

15 */4 * * *   ...

translates to at minute 15 past every 4th hour starting from hour 00 ... not from reboot.

You might want:

@reboot sleep 4h ...

That is wait for 4 hours after the system starts then run the command ... That, however, will run the command only once after each reboot ... To continue running the command every 4 hours after each reboot until shutdown, then you can add your command/s to a script file like so:

#!/bin/bash

while true; do

command/s here will first run immediately after boot

sleep 4h

command/s here will first run 4 hours after boot

done

then use that script file in the crontab line like so:

@reboot /bin/bash /full/path/to/scriptfile
Raffa
  • 32,237
  • Note that unless all those other commands run instantly, then the period will be greater than 4 hours, and the start time will drift. Depending on the nature of the task, that may or may not be significant. (Fixing it isn't trivial; you might need to store the current time immediately after the sleep, and then immediately before the next sleep add 4 hours to it, subtract the current time, and sleep for the difference.) If an alternative is available (such as systemd, as per steeldriver's answer), that might be easier overall. – gidds Jan 12 '23 at 23:22
  • This option will keep the process active constantly. – chribonn Jan 16 '23 at 08:41
  • @chribonn Yes, the script will do the scheduling job after it is run for the first time by cron ... In fact, if you use the Ubuntu desktop, you can for example run it as a startup application like this https://askubuntu.com/a/1413670 ... So it will be automatically started after user login without needing cron at all ... It's good to have choices ... and all roads lead to Rome as they say :-) – Raffa Jan 16 '23 at 10:20
0

Have you considered the use of at as a scheduler?

At boot time, run a script that schedules an 'at' job four hours hence and passes the time it ran to something the at job can read (e.g. a file somewhere, e.g. within the at job itself, e.g. a parameter passed to the 'at' job, there are many ways you can pass the parameter).

When the 'at' job runs, at some point in the script run it schedules another 'at' job exactly 4 hours after it was launched. This will only suffer schedule creep or not-four-hourness at times your system clock enters or exist DST (twice a year if the timezone it runs in uses daylight saving) or when the system clock gets a time adjustment...

houninym
  • 101