More dynamic cronjobs ===================== By George Mandis https://george.mand.is/2025/09/more-dynamic-cronjobs Sunday, September 21st 2025 I remember learning about cronjobs in the early 2000s. I could tell the computer to go _do_ something, on a recurring basis, forever, even when I wasn't there. They felt like magic! We didn't have [Crontab.guru](https://crontab.guru) or AI to ask for figuring out some of the more complex specifications. Just the [man pages](https://man.openbsd.org/crontab.5) and good old-fashioned trial and error—mostly error in my case. But while you could do fun, complex specifications of recurring intervals, you couldn't quite specify something quite as dynamic as "run this script every Tuesday at 7am _unless it's the last Tuesday_ of the month..." Or at least, you couldn't strictly through the crontab specification syntax. But I had a recent, mildly embarrassing epiphany that it's not hard at all to add arbitrary checks to your crontab to account for more complex and dynamic scenarios. Want to run a script every Tuesday of the month at 7am _except_ for the last Tuesday? That's easy—set up your crontab to run every Tuesday at 7am, but add a little check to make sure the _next_ week is still part of the same month: ```shell 0 7 * * Tue [ "$(date -v+7d '+%m')" = "$(date '+%m')" ] && /path/to/your_command ``` If it's not part of the same month, that means we're on the _last_ Tuesday for the month and the script won't run. **Note:** *The `-v` flag is for the macOS/BSD flavors of `date`. On Linux you'd want to use `-d +7 days` instead.* This really has nothing to do with cronjobs at all and everything to do with the [POSIX "test" command](https://www.unix.com/man_page/posix/1p/test/) which is the thing we're using with those square brackets. I'm used to seeing and utilizing them in shell scripts, but for whatever reason I never thought to reach for that tool here in the crontab. You could just as easily rewrite it like this, skipping the bracket shorthand, which is probably easier to read: ```shell 0 7 * * Tue test "$(date -v+7d '+%m')" = "$(date '+%m')" && /path/to/your_command ``` It never crossed my mind until recently to add slightly more complex checks at the crontab level. ### Other clever cronjob things you can do: #### Holiday-only cronjobs Maybe fetch a list of all the US Holidays for a given year and store them in a handy `HOLIDAYS.txt` file somewhere: ```shell curl -s https://date.nager.at/api/v3/PublicHolidays/2025/US | jq -r '.[].date' > HOLIDAYS.txt ``` Now you can update your cronjob to run every Tuesday at 7am _except_ on Holidays: ```shell 0 7 * * Tue ! grep -qx "$(date +%F)" HOLIDAYS.txt && /path/to/your_command ``` Or inversely, maybe run a holiday-only script that checks once a day ```shell @daily grep -qx "$(date +%F)" HOLIDAYS.txt && /path/to/your_special_holiday_command ``` #### Only run on sunny days The [National Weather Service](https://weather.gov) makes all kinds of fun data available (if you can find it...). How about a script that runs every hour, but only when the weather is clear? ```shell @hourly curl -s "https://api.weather.gov/gridpoints/TOP/32,81/forecast/hourly" | jq -r '.properties.periods[0].shortForecast' | grep -qi clear && /path/to/your_command ``` Or maybe when the weather is cloudy? ```shell @hourly curl -s "https://api.weather.gov/gridpoints/TOP/32,81/forecast/hourly" | jq -r '.properties.periods[0].shortForecast' | grep -qi cloudy && /path/to/your_command ``` #### Only run when there's something newsworthy Or maybe we get in line with every-other-startup I'm aware of and throw AI at the problem, only running our script when the LLM gods have decided there is something newsworthy: ```shell @hourly curl -s "https://news.google.com/rss?hl=en-US&gl=US&ceid=US:en" | llm --system "Reply strictly 'yes' or 'no'. Does anything in the news today suggest it is a good reason to run a script that I only want to send when the world is on fire and crazy and terrible things are happening?" | tr -d '[:space:]' | tr '[:upper:]' '[:lower:]' | grep -qx yes && /path/to/oh_no ```