Cron jobs

Basic task scheduling on Unux based systems

More here about the commands as well as cron expressions: https://www.doabledanny.com/cron-jobs-on-macarrow-up-right

Check your cron expression: https://crontab.guru/arrow-up-right

Understanding Job Scheduling: cron, crontab, and launchd

Core Components

1. cron (The Traditional Unix Scheduler)

What it is:

  • A time-based job scheduler found on Unix-like systems (Linux, BSD, macOS)

  • A daemon process (/usr/sbin/cron or /usr/sbin/crond) that runs continuously in the background

  • Checks every minute for scheduled jobs to run

  • Reads schedule files and executes commands at specified times

Where it reads from:

/var/spool/cron/crontabs/username  # Individual user crontabs (Debian/Ubuntu)
/var/spool/cron/username           # Individual user crontabs (Red Hat/CentOS)
/etc/crontab                       # System-wide crontab
/etc/cron.d/                       # Additional system cron files
/etc/cron.hourly/                  # Scripts run hourly
/etc/cron.daily/                   # Scripts run daily
/etc/cron.weekly/                  # Scripts run weekly
/etc/cron.monthly/                 # Scripts run monthly

2. crontab (The Configuration Tool and File Format)

What it is:

  • Both a command-line tool AND the file format used by cron

  • Each user has their own crontab file

  • Contains the schedule and commands in a specific syntax

Common commands:

File format:

For user crontabs (edited with crontab -e):

For system-wide /etc/crontab:

Format explained:

  • minute: 0-59

  • hour: 0-23 (24-hour format)

  • day: 1-31

  • month: 1-12

  • weekday: 0-7 (0 and 7 are Sunday, 1 is Monday)

  • user: (only in /etc/crontab and /etc/cron.d/*) which user runs the command

  • command: the script or command to execute

Special syntax:

Common practices:


3. launchd (macOS-Specific Alternative)

What it is:

  • Apple's replacement for cron and other Unix init systems

  • The first process (PID 1) on macOS

  • Manages services, daemons, and scheduled tasks

  • Actually starts and manages the cron daemon when cron is used on macOS

Why it matters for macOS users:

  • Apple has deprecated cron in favor of launchd

  • cron still works but may require Full Disk Access permissions on modern macOS

  • launchd offers advantages: runs missed jobs, better logging, macOS security integration

  • If developing primarily for macOS, learn launchd; if targeting Linux servers, focus on cron

The relationship on macOS:


launchd Job Types (macOS Only)

LaunchDaemons (System-wide)

  • Location: /Library/LaunchDaemons/

  • Run as root or specified user

  • Start at boot time

  • For system-level services

LaunchAgents (User-level)

  • Location: ~/Library/LaunchAgents/ (per-user) or /Library/LaunchAgents/ (all users)

  • Run as the logged-in user

  • Start at user login

  • For user-specific tasks

Example scheduled task:

Common launchd commands:


Practical Tips

Debugging cron jobs:

Common pitfalls:

  • Cron jobs run with minimal environment variables (PATH, HOME, etc.)

  • Always use absolute paths in cron commands

In your script itself:

  • Remember that cron doesn't run missed jobs if the system was off. If your computer or server is turned off or asleep at the scheduled time, cron simply skips that job. It doesn't "catch up" when the system comes back online.

  • Email notifications are sent by default unless output is redirected

What do 1>&2 or 2>&1 mean?

Whenever you use this kind of cron expression:

  • For example: ***** python3 main.pyarrow-up-right>> output.log 2>&1 , the >> will redirect the output to a file (in this case output.log but can be any file like .txt or else). 2>&1 will make sure that not only stdout gets redirected to that file but also stderr will go there to.

  • Note: each print statement in your Python code (or e.g. Golang’s fmt.Println()) will be logged because print() writes to stdout.

  • If you want to be more selective about what gets logged, you could:

    1. Use Python's logging module instead of print()

    2. Remove the redirection from the bash script

    3. Or redirect only specific parts of the output

Last updated