Task scheduling in Linux is not just a matter of convenience, but often a necessity. When dealing with one-time actions — such as running a backup at a specific time or sending a notification after a long process finishes — the `at` and `cron` tools seem like the natural choices. But which one works better? Where is the line between simplicity and flexibility, and when does one of them fail?
Basic differences between `at` and `cron` — what to know before choosing
Both at and cron are used for task scheduling, but their approach to this topic differs significantly. at was created with one-time events in mind, which are meant to run at a strictly defined moment in the future. Its syntax is intuitive and clear, making it an ideal tool for quickly scheduling an action that should not repeat. On the other hand, cron is a more powerful tool, optimized for recurring tasks — those that should run every hour, every day, every week, or at any user-defined time interval.
The following table presents the key differences between these tools:
| Criterion | at |
cron |
|---|---|---|
| Task type | One-time (e.g., "run script tomorrow at 15:00") | Recurring (e.g., "run script every 2 hours") |
| Syntax | Simple: echo "komenda" | at 14:30 2024-05-20 |
Complex: requires editing crontab (e.g., 30 14 20 5 * /ścieżka/skrypt) |
| Date flexibility | Very high: supports complex patterns (e.g., "now + 30 minutes", "tomorrow at midnight") | Limited: time intervals only (e.g., every minute, every hour) |
| Priorities | No priorities — order depends on addition time | Ability to set priorities by user (e.g., using nice) |
| Logging | Standardly saves commands and output to /var/log/atd (depending on distribution) |
Logs in /var/log/syslog or /var/log/cron (depending on system) |
When `at` works better than `cron` — practical examples
The choice between at and cron depends primarily on the nature of the scheduled task. Below you will find specific scenarios where at is not only a convenient but also a safe choice:
-
Executing a one-time action at a specific time — e.g., sending an email in 10 minutes at 15:00:
echo "echo 'Temat: Raport dzienny' | mail -s 'Raport' admin@example.com" | at 15:00In this case,
atallows for precise specification of the execution time without the need to create an entry incrontab. -
Automating tasks dependent on external events — e.g., starting a file conversion after its download finishes:
wget https://example.com/duzy_plik.iso && echo "/ścieżka/do/konwersji.sh" | at now + 5 minutesThanks to
at, you can schedule an action to execute right after the previous process finishes, even if you don't know exactly when that will happen. -
Prototyping and testing scripts — e.g., quickly checking script behavior at a specific hour:
echo "ls -la /tmp > /var/log/test.log" | at now + 2 minutesThis is much faster than editing
crontab, especially in development environments. -
Resource-constrained environments — e.g., Docker containers with a minimal image (e.g., Alpine Linux), where
cronis not available or is too resource-intensive:echo "backup.sh" | at 02:00 tomorrow
Comparative example:
Suppose you want to schedule a backup for 2:00 AM. Using at, it looks like this:
echo "/ścieżka/do/backup.sh" | at 02:00 2024-05-21
Conversely, with cron, you would have to define an entry in crontab:
0 2 * * * /ścieżka/do/backup.sh
The first solution is clearer and less prone to syntax errors, especially for users who rarely use cron.
Technical limitations of `at` — what can go wrong?
Despite its advantages, at is not a perfect tool. Its main limitations stem from its simplicity and specific purpose. Here are the most common problems users may encounter:
1. Lack of user environment support
at runs tasks in a minimal environment, often ignoring variables defined in .bashrc or .profile. This can lead to errors if the script depends on specific environment variables (e.g., $PATH).
Solution: Define the environment in the script or use full paths for commands:
echo "#!/bin/bash
export PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin
/ścieżka/do/backup.sh" > /tmp/backup_env.sh
echo "/tmp/backup_env.sh" | at 02:00
2. Job queue issues
If the system is overloaded, at tasks may be delayed or skipped. This happens because the atd daemon has no prioritization mechanism — it operates on a FIFO (First-In-First-Out) queue basis.
Solution: Monitor the job queue and remove old or unnecessary entries:
atq # Lista zadań w kolejce
atrm 123 # Usunięcie zadania o ID 123
3. Permissions — who can use `at`?
By default, access to at is restricted by the /etc/at.allow and /etc/at.deny files. If a user is not listed in either of them, the system will return an error:
You do not have permission to use at.
Solution: Add the user to /etc/at.allow or remove them from /etc/at.deny:
echo "użytkownik" | sudo tee -a /etc/at.allow
4. `atd` daemon errors
Sometimes the atd daemon does not work correctly, resulting in tasks not being executed. The most common causes are:
- The daemon was not started:
sudo systemctl enable --now atd - Lock file issue: remove
/var/run/atd.pidand restart the daemon - Lack of free disk space (tasks are saved in
/var/spool/at)
Diagnostics: Check the daemon status:
sudo systemctl status atd
journalctl -u atd --since "1 hour ago"
5. Time zone handling
at does not always account for the user's time zone. This can lead to unexpected results if the user is operating in a different time zone than the system.
Solution: Use the TZ variable in the script or explicitly specify the time in UTC:
echo "TZ=UTC /ścieżka/do/skrypt.sh" | at 02:00
Installing `at` on popular distributions — a step-by-step guide
Although at is widely available, it is not always installed by default. Below you will find instructions for the most popular Linux distributions:
| Distribution | Installed by default? | Package to install | Additional steps |
|---|---|---|---|
| Debian / Ubuntu | No | at |
Start daemon: sudo systemctl enable --now atd |
| RHEL / CentOS / Fedora | Yes (since RHEL 7+) | — | Check if daemon is running: sudo systemctl status atd |
| Arch Linux | No | at |
— |
| openSUSE | No | at |
— |
| Alpine Linux | Yes | — | Daemon starts automatically with busybox |
Installation on Debian/Ubuntu:
sudo apt update
sudo apt install at
sudo systemctl enable --now atd
Installation on Arch Linux:
sudo pacman -S at
Checking if the daemon is running:
sudo systemctl status atd
Alternatives to `at` — when to consider other tools?
Although at is an excellent solution for one-time tasks, in some cases it is worth considering alternatives. Below we compare the most popular ones:
`systemd timers` — more flexible but more complex
systemd timers is a tool built into the systemd system, which offers greater flexibility than at, but requires knowledge of .timer and .service file syntax. It is ideal for users who already use systemd and want to integrate task scheduling with other system services.
Example: Create a file /etc/systemd/system/backup.timer:
[Unit]
Description=Backup o północy
[Timer]
OnCalendar=*-*-* 02:00:00
Persistent=true
[Install]
WantedBy=timers.target
Then activate the timer:
sudo systemctl enable --now backup.timer
Pros:
- Precise triggers (e.g., based on system events)
- Better integration with
systemdlogs - Ability to run tasks in response to system events
Cons:
- Syntax is more complex than
at - Requires knowledge of
systemd
`fcron` — for recurring tasks with irregular intervals
fcron is an alternative to cron that offers greater flexibility in defining recurring tasks. It is particularly useful in environments where tasks need to run irregularly, e.g., "every 3 days" or "every other Tuesday".
Example: Define a task in /etc/fcrontab:
3 0 * * 1,3,5 /ścieżka/do/skrypt.sh
This means the script will run every Monday, Wednesday, and Friday at 3:00.
Pros:
- Support for tasks with irregular intervals
- Better handling of environments with limited computing power
Cons:
- Less popular than
cron - Less documentation and community support
`anacron` — for systems with non-continuous operation
anacron is a tool designed for systems that are not running all the time (e.g., laptops). It ensures that scheduled tasks are executed even if the system was powered off at the scheduled time.
Example: Define a task in /etc/anacrontab:
7 10 backup.daily /ścieżka/do/backup.sh
This means the script will run every 7 days; if the system was off, it will run upon the next startup.
Pros:
- Works even with irregular system operation
- Simple configuration
Cons:
- Limited to daily/weekly tasks
- Not suitable for one-time tasks
Security when using `at` — how to avoid pitfalls?
Although at is a simple tool, its improper use can lead to security issues. Here are best practices that will help you avoid the most common pitfalls:
1. Restrict access to `at`
By default, access to at is controlled by the /etc/at.allow and /etc/at.deny files. The safest approach is to create the /etc/at.allow file and place only authorized users in it.
sudo touch /etc/at.allow
echo "admin" | sudo tee -a /etc/at.allow
echo "developer" | sudo tee -a /etc/at.allow
Users not listed in either file will not be able to use at.
2. Avoid sensitive commands in the `at` queue
at tasks are saved in /var/spool/at in a format readable by administrators. If you plan to execute a command that contains passwords or sensitive data, consider using scripts with restricted permissions or external secret management tools.
3. Log task results
To monitor task execution, redirect the output to a log file:
echo "/ścieżka/do/skrypt.sh > /var/log/at_job.log 2>&1" | at 02:00
This will allow you to easily verify whether the task completed successfully.
4. Remove old tasks
Tasks that should have been completed long ago should be removed from the queue. You can do this manually using atrm or automate this process with a simple script.
# Usuń wszystkie zadania starsze niż 7 dni
atq | awk '$1 < systime() - 604800 {print $1}' | xargs -I {} atrm {}
5. Avoid running `at` tasks as root
If possible, run tasks from a user account with minimal privileges. Using root should be limited to tasks that require administrator privileges.
Summary — when to choose `at` and when `cron`?
The choice between at and cron depends primarily on the nature of your task:
-
Use
atwhen:- You are dealing with a one-time task at a strictly defined time.
- You need a simple and fast scheduling method.
- You are working in an environment where
cronis not available (e.g., minimal containers). - You want to quickly test script behavior.
-
Use
cronwhen:- You are dealing with a recurring task (e.g., every hour, every week).
- You need greater flexibility in defining intervals.
- You want to prioritize tasks or set time limits.
If you are still in doubt, start with at. Its simplicity and readability make it an excellent starting point for task automation in Linux. When your needs go beyond one-time actions, you can easily switch to cron or its alternatives.
Sources
- https://www.tecmint.com/at-command-linux/
- https://man7.org/linux/man-pages/man1/at.1.html
- https://man7.org/linux/man-pages/man8/cron.8.html
- https://bugzilla.redhat.com/
- https://wiki.archlinux.org/title/At
- https://packages.debian.org/search?keywords=at
- https://archlinux.org/packages/?name=at
- https://access.redhat.com/documentation/en-us/red_hat_enterprise_linux/9/html/considerations_in_adopting_rhel_9/package-list
- https://linuxize.com/post/at-vs-cron/
- https://www.digitalocean.com/community/tutorials/how-to-use-the-at-command-to-schedule-one-time-tasks-on-linux
- http://manpages.ubuntu.com/manpages/focal/man5/at.allow.5.html
- https://wiki.archlinux.org/title/At#Troubleshooting
Comments