crontab — Schedule recurring commands on Unix via per-user crontab files across all 5 shells
Equivalents in every shell
crontab -eEdits the current user's crontab in `$EDITOR`. Format per line: `m h dom mon dow command`. Examples: `*/5 * * * * /path/script.sh` (every 5 min); `0 3 * * * backup.sh` (3 AM daily); `0 0 * * 0 weekly.sh` (Sunday midnight). `crontab -l` lists, `crontab -r` removes (no confirmation — dangerous). The PATH inside cron jobs is MINIMAL — typically `/usr/bin:/bin`. Set `PATH=...` as a line in the crontab itself or use absolute paths.
crontab -eSame Unix binary. macOS gotcha: macOS 10.15+ runs many `cron` jobs under sandboxed restrictions — your job may need Full Disk Access granted to `cron` in System Settings → Privacy & Security to touch user files. The Apple-blessed alternative is `launchd` plists in `~/Library/LaunchAgents/` (richer triggers, including "run on file change", "run at login", "run after sleep") — `crontab` still works but is on the deprecated path.
crontab -eSame external. Fish-specific: the COMMAND in crontab is run via `/bin/sh` (POSIX), NOT fish. So a crontab line like `0 * * * * source ~/.config/fish/config.fish; my-fish-function` does NOT work — sh doesn't understand fish. Wrap fish scripts: `0 * * * * /usr/bin/fish -c "my-fish-function"`. Or, put the actual logic in a portable shell script and invoke that.
Register-ScheduledTask -TaskName Backup -Trigger (New-ScheduledTaskTrigger -Daily -At 3am) -Action (New-ScheduledTaskAction -Execute pwsh -Argument "-File C:\backup.ps1")Windows scheduled tasks via the `ScheduledTasks` module. Richer trigger surface than cron (logon, system idle, on-event-log-event, at-startup, etc). `Get-ScheduledTask` lists, `Get-ScheduledTaskInfo -TaskName x` shows last/next run times. Multi-step task setup: `New-ScheduledTaskTrigger` + `New-ScheduledTaskAction` + `New-ScheduledTaskPrincipal` (run-as identity) + `New-ScheduledTaskSettingsSet` (battery / network conditions) + `Register-ScheduledTask` to install. Programmatic; the GUI is `taskschd.msc`.
schtasks /create /sc DAILY /st 03:00 /tn Backup /tr "C:\backup.bat"`schtasks` is the Windows builtin equivalent of `crontab`. Flags: `/sc <schedule>` (MINUTE / HOURLY / DAILY / WEEKLY / MONTHLY / ONCE / ONSTART / ONLOGON / ONIDLE), `/st HH:MM` start time, `/tn` task name, `/tr` command to run. `schtasks /query` lists, `schtasks /delete /tn Backup /f` removes. The older `at` command still works for simple "run once at this time" but is deprecated since Win8.
Worked examples
List current scheduled tasks
crontab -lcrontab -lcrontab -lGet-ScheduledTaskschtasks /querySchedule a daily 3 AM backup
(crontab -l 2>/dev/null; echo "0 3 * * * /path/backup.sh") | crontab -crontab -e # then add: 0 3 * * * /path/backup.shRegister-ScheduledTask -TaskName Backup -Trigger (New-ScheduledTaskTrigger -Daily -At 3am) -Action (New-ScheduledTaskAction -Execute pwsh -Argument "-File C:\backup.ps1")schtasks /create /sc DAILY /st 03:00 /tn Backup /tr "C:\backup.bat"Remove a scheduled task
crontab -l | grep -v "/path/backup.sh" | crontab -Unregister-ScheduledTask -TaskName Backup -Confirm:$falseschtasks /delete /tn Backup /fGotchas
- `crontab -r` removes the ENTIRE crontab without confirmation. Many Unix admins have lost weeks of automation by typing `crontab -r` when they meant `crontab -e`. Defense: always `crontab -l > ~/cron.backup` before edits, and consider aliasing `crontab` to a wrapper that takes a snapshot first. Some Linux distros patch in a `-i` (interactive confirm) flag — check `crontab --help`.
- Cron's environment is NEARLY EMPTY — no `PATH`, no `HOME`, no DISPLAY, none of the variables your interactive shell has. A script that runs fine when you `bash script.sh` from the terminal will SILENTLY FAIL from cron with `command not found`. Fix: set absolute paths (`/usr/bin/node` not `node`) or put `PATH=/usr/local/bin:/usr/bin:/bin` as the first non-comment line of the crontab.
- Cron output goes to MAIL by default — if `mail` is configured, you get an email per job. If not, the output is silently dropped. Most servers in 2026 do not have local mail configured, so cron output vanishes — your script reports "it worked!" to /dev/null. ALWAYS redirect explicitly in the crontab line: `0 3 * * * backup.sh >> /var/log/backup.log 2>&1`.
- macOS sandbox restrictions: in 10.15+, `cron` jobs that touch `~/Documents`, `~/Desktop`, etc fail unless `cron` itself has Full Disk Access. Grant it via System Settings → Privacy & Security → Full Disk Access → `+` → `/usr/sbin/cron`. This is the most common "my crontab worked on Linux but does nothing on macOS" cause. Apple's preferred path is `launchd` (`launchctl load ~/Library/LaunchAgents/foo.plist`), which has its own permission model.
- Windows `schtasks /create` defaults to running as the CURRENT USER, but the task only runs when that user is logged on. To run "at 3am every night even when logged off", add `/ru SYSTEM` (run as SYSTEM, no logon required) or `/ru <user> /rp <password>` (cached credentials — credential dialog on machines with Credential Guard). The pwsh equivalent is `Register-ScheduledTask -Principal (New-ScheduledTaskPrincipal -UserId SYSTEM -LogonType ServiceAccount)`.