How to Schedule Tasks in Red Hat Enterprise Linux
Red Hat Enterprise Linux (RHEL) is a leading enterprise-grade Linux distribution widely regarded as the gold standard for mission-critical server environments. It provides robust, secure, and scalable solutions for organizations ranging from small bu...

Red Hat Enterprise Linux (RHEL) is a leading enterprise-grade Linux distribution widely regarded as the gold standard for mission-critical server environments. It provides robust, secure, and scalable solutions for organizations ranging from small businesses to Fortune 500 companies, powering everything from web servers and databases to cloud infrastructure and containerized applications.
You can use RHEL's task scheduling capabilities in scenarios like automating system maintenance (for example, log rotation or backup operations), managing routine administrative tasks (like user account cleanup or security updates), or orchestrating complex workflows in enterprise environments. These scheduling tools are essential for maintaining system health and ensuring that critical operations run without manual intervention.
For system administrators, think of task scheduling as the backbone of automated system management, enabling you to set up processes that run reliably in the background while you focus on more strategic initiatives. Its power lies in its flexibility and reliability, making it an indispensable skill for anyone managing Linux systems in production environments.
In this tutorial, you’ll learn how to schedule tasks in Red Hat Enterprise Linux using various built-in tools and techniques. This content is part of Schedule Future Tasks, which is Chapter 2 of the Red Hat System Administration (RH134) course. RH134 is a fundamental course for the Red Hat Certified System Administrator (RHCSA) certification, one of the most respected credentials in the Linux administration field.
This hands-on tutorial provides practical experience with the scheduling concepts covered in the RH134 curriculum, giving you the skills needed to automate tasks effectively in enterprise RHEL environments.
Here's what we'll cover:
Prerequisites
This tutorial is designed to be beginner-friendly! You just need basic familiarity with using the Linux command line. If you can navigate directories and run simple commands, you're ready to start.
For those looking to deepen their RHEL knowledge, the RHEL Skill Tree offers comprehensive hands-on labs including RH124, RH134, RH294, and other courses for RHCSA and RHCE certifications.
Don't worry if you're new to Red Hat Enterprise Linux – I'll explain everything step by step, and these concepts work on most Linux distributions too.
How to Schedule a One-time Job with 'at'
First, let’s learn how to schedule a job to run once at a future time using the at
command. The at
command is useful for executing commands that don’t need to be run repeatedly. We will schedule a simple job, inspect its details, and then remove it.
In this tutorial, we will work directly on the local system to learn task scheduling. You’ll execute all commands in your current terminal environment.
Let's schedule a job to print the current date and time into a file named ~/myjob.txt
in your home directory. We'll schedule it to run 3 minutes from now:
at now + 3 minutes << EOF
date > ~/myjob.txt
EOF
The warning: commands will be executed using /bin/sh
message is normal. The job N at ...
output indicates the job number and the scheduled execution time. Make a note of the job number, as you will need it later.
Next, let's schedule another job interactively. This method is useful for entering multiple commands or more complex scripts. We will schedule a job to append "Hello from at job!" to ~/at_output.txt
5 minutes from now:
at now + 5 minutes
After typing the command and pressing Enter, you will see an at>
prompt. Type your command and then press Ctrl+d
to finish:
at > echo "Hello from at job!" >> ~/at_output.txt
at > Ctrl+d
To view the jobs currently in the at
queue, use the atq
command. This command lists all pending at
jobs for the current user.
atq
The output will show the job number, the scheduled time, the queue, and the user who scheduled it.
You can inspect the commands that a specific at
job will run using the at -c
command followed by the job number. Replace N
with one of the job numbers you noted earlier.
at -c N
This command will display the shell script that at
will execute for that job. You should see the date > ~/myjob.txt
or echo "Hello from at job!" >> ~/at_output.txt
command within the output.
Finally, to remove a scheduled at
job, use the atrm
command followed by the job number. Let's remove the first job we scheduled. Replace N
with the job number of your first job.
atrm N
After removing the job, you can use atq
again to verify that it is no longer in the queue.
atq
You should now only see the second job (if it hasn't executed yet) or an empty queue if both jobs have been removed or executed.
This completes the first step of scheduling one-time jobs with the at
command.
How to Manage 'at' jobs
Now, let’s delve deeper into managing at
jobs, including scheduling jobs with different queues and verifying their execution. Understanding at
queues can be useful for prioritizing tasks or separating different types of one-time jobs.
We will continue working on the local system to explore more advanced at
job management features.
The at
command allows you to specify a queue using the -q
option. Queues are single letters from a
to z
. Queue a
is the default, and jobs in queues a
through z
are executed with decreasing niceness (priority). Queue a
has the highest priority, and queue z
has the lowest. Queue b
is reserved for batch jobs.
Let's schedule a job in queue g
(a lower priority queue) to run in 2 minutes. This job will create a file named ~/queue_g_job.txt
with a timestamp:
at -q g now + 2 minutes << EOF
date > ~/queue_g_job.txt
EOF
You will see output similar to job N at ...
. Note down this job number.
Next, let's schedule another job, this time in queue b
(batch queue), which is typically used for jobs that can run when system load is low. This job will append "Batch job executed!" to ~/batch_job.txt
. We'll schedule it to run 4 minutes from now:
at -q b now + 4 minutes << EOF
echo "Batch job executed!" >> ~/batch_job.txt
EOF
Again, note down the job number.
To see all pending jobs, including those in different queues, use atq
.
atq
You should now see both jobs listed, with their respective queue letters (g
and b
).
Now, wait for your scheduled jobs to execute. Wait for at least 5 minutes to allow all jobs to complete. You can check if the files created by your at
jobs exist and contain the expected content.
Check ~/queue_g_job.txt
:
cat ~/queue_g_job.txt
You should see a date and time string.
Check ~/batch_job.txt
:
cat ~/batch_job.txt
You should see "Batch job executed!".
If the files are not present or empty, it might mean the jobs haven't executed yet, or there was an issue with the command. You can re-check atq
to see if they are still pending.
How to Schedule Recurring User Jobs with 'crontab'
Next, you’ll learn how to schedule recurring tasks for a specific user using crontab
. Unlike at
jobs, which run once, cron
jobs run repeatedly at specified intervals. This is ideal for routine maintenance, data backups, or generating reports.
We will continue working on the local system to learn about user crontab management.
The crontab
command allows users to create, edit, and view their own cron
jobs. Each user has their own crontab
file.
To edit your crontab
file, use the crontab -e
command. This will open your crontab
file in the default text editor (usually vim
).
crontab -e
Vim editor instructions:
Press
i
to enter insert mode (you'll see-- INSERT --
at the bottom)Use arrow keys to navigate
To save and exit: Press
Esc
to exit insert mode, then type:wq
and pressEnter
To exit without saving: Press
Esc
, then type:q!
and pressEnter
Inside the editor, you will add a new line to define your cron
job. A cron
entry has five time-and-date fields, followed by the command to be executed. The fields are:
Minute (0-59)
Hour (0-23)
Day of Month (1-31)
Month (1-12)
Day of Week (0-7, where 0 or 7 is Sunday)
You can use *
as a wildcard to mean "every" for a field, or /
to specify step values (for example, */5
for every 5 minutes).
Let's schedule a job that appends the current date and time to a file named ~/my_cron_log.txt
every minute. This will allow us to quickly observe the cron
job in action.
Follow these steps in Vim:
Press
i
to enter insert modeAdd the following line to the
crontab
file:
* * * * * /usr/bin/date >> ~/my_cron_log.txt
Press
Esc
to exit insert modeType
:wq
and pressEnter
to save and exit
You should see a message indicating that a new crontab
has been installed:
crontab: installing new crontab
To verify that your cron
job has been successfully added, you can list your crontab
entries using the crontab -l
command:
crontab -l
You should see the line you just added:
* * * * * /usr/bin/date >> ~/my_cron_log.txt
Now, wait for a minute or two to allow the cron
job to execute at least once. You can check the current time to see when the next minute mark will occur:
date
After waiting for at least two minutes to allow the cron job to execute a couple of times, check the content of the ~/my_cron_log.txt
file.
cat ~/my_cron_log.txt
You should see one or more lines, each containing a date and time, indicating that your cron
job has executed.
Mon Apr 8 10:30:01 AM EDT 2025
Mon Apr 8 10:31:01 AM EDT 2025
How to Manage User 'crontab' Entries
Now you will learn more advanced techniques for managing user crontab
entries, including editing existing jobs, adding multiple jobs, and understanding special cron
strings. Effective crontab
management is crucial for automating routine tasks.
We will continue working on the local system to explore advanced crontab management techniques.
Let's start by adding a new cron
job. This job will append "Hello from cron!" to ~/cron_messages.txt
every two minutes.
Open your crontab
for editing:
crontab -e
In Vim:
Press
i
to enter insert modeAdd the following line to the
crontab
file:
*/2 * * * * echo "Hello from cron!" >> ~/cron_messages.txt
Press
Esc
to exit insert modeType
:wq
and pressEnter
to save and exit
Verify that the entry is added:
crontab -l
You should see the newly added line.
Now, let's add another cron
job that runs daily at 08:00 AM. This job will record the disk usage of your home directory to ~/disk_usage.log
.
Open your crontab
for editing again:
crontab -e
In Vim:
Press
i
to enter insert modeAdd the following line below the previous one:
0 8 * * * du -sh ~ >> ~/disk_usage.log
Press
Esc
to exit insert modeType
:wq
and pressEnter
to save and exit
Verify that both entries are present:
crontab -l
You should now see both cron
jobs listed.
cron
also supports special strings that can simplify common schedules. These include @reboot
, @yearly
, @annually
, @monthly
, @weekly
, @daily
, @midnight
, and @hourly
. For example, @hourly
is equivalent to 0 * * * *
.
Let's add a job that runs hourly and records the system uptime to ~/uptime_log.txt
.
Open your crontab
for editing:
crontab -e
In Vim:
Press
i
to enter insert modeAdd the following line:
@hourly uptime >> ~/uptime_log.txt
Press
Esc
to exit insert modeType
:wq
and pressEnter
to save and exit
Verify all three entries:
crontab -l
You should now see all three cron
jobs.
To demonstrate the effect of these jobs, we will wait for a short period. Since the jobs are scheduled at different intervals, we won't see all of them execute immediately, but we can verify the setup.
Wait for at least 3 minutes to allow the */2
job to run at least once.
Check the ~/cron_messages.txt
file:
cat ~/cron_messages.txt
You should see at least one "Hello from cron!" message.
Hello from cron!
The ~/disk_usage.log
and ~/uptime_log.txt
files might not be created yet, depending on the current time, as they are scheduled for daily and hourly execution, respectively. The important part is that their entries are correctly configured in your crontab
.
How to Schedule Recurring System Jobs with cron
Directories
In this step, you will learn how to schedule recurring system-wide tasks using cron
directories. Unlike user crontab
entries, which are specific to a user, system cron
jobs are managed by the root user and affect the entire system. These are typically used for system maintenance, log rotation, and other administrative tasks.
We will continue working on the local system to explore system-wide cron job configuration.
System-wide cron
jobs are defined in /etc/crontab
or by placing scripts in specific directories:
/etc/cron.hourly/
: Scripts in this directory run once an hour./etc/cron.daily/
: Scripts in this directory run once a day./etc/cron.weekly/
: Scripts in this directory run once a week./etc/cron.monthly/
: Scripts in this directory run once a month.
These directories are processed by the run-parts
utility, which executes all executable files within them.
To manage system cron
jobs, you need root privileges. Since the labex user has sudo access, we can use sudo
for the required commands.
Let's create a simple script that logs a message to the system log. We will place this script in /etc/cron.hourly/
to make it run hourly.
First, create the script file /etc/cron.hourly/my_hourly_script
:
sudo nano /etc/cron.hourly/my_hourly_script
Add the following content to the file:
#!/bin/bash
logger "Hourly cron job executed at $(date)"
Save and exit the editor (Ctrl+o
, Enter
, Ctrl+x
in nano
).
Next, you need to make the script executable. Without execute permissions, run-parts
will ignore it.
sudo chmod +x /etc/cron.hourly/my_hourly_script
Now, let's verify that the script is executable:
ls -l /etc/cron.hourly/my_hourly_script
You should see x
in the permissions, for example: -rwxr-xr-x
.
Since cron.hourly
jobs run once an hour, we can't wait for a full hour to verify its execution in this tutorial. But we can manually trigger the run-parts
command for the hourly directory to simulate its execution.
sudo run-parts /etc/cron.hourly/
This command will execute all executable scripts in /etc/cron.hourly/
. The script we created uses the logger
command to write messages to the system log.
In a real RHEL system, you would be able to check the system logs using journalctl
or /var/log/messages
to verify that the script executed successfully.
This completes the system cron job management step. The script will remain in place and would execute hourly in a real system environment.
How to Configure systemd
Timers for Recurring Tasks
Next, you will learn about systemd
timers, which are a modern alternative to cron
for scheduling tasks on Linux systems. systemd
timers offer more flexibility and better integration with the systemd
ecosystem.
systemd
timers work in conjunction with systemd
service units. A timer unit (.timer
file) defines when a task should run, and a service unit (.service
file) defines what task should be executed.
We will continue working on the local system to explore systemd timer configuration.
You will need root privileges to create systemd
unit files in system directories. Since the labex user has sudo access, we can use sudo
for the required commands.
Let's create a simple service that logs a message to a file. We will place this service unit file in /etc/systemd/system/
which is where custom service units are typically stored.
Create the service unit file /etc/systemd/system/my-custom-task.service
:
sudo nano /etc/systemd/system/my-custom-task.service
Add the following content to the file:
[Unit]
Description=My Custom Scheduled Task
[Service]
Type=oneshot
ExecStart=/bin/bash -c 'echo "My custom task executed at $(date)" >> /var/log/my-custom-task.log'
Save and exit the editor (Ctrl+o
, Enter
, Ctrl+x
in nano
).
Next, create the timer unit file /etc/systemd/system/my-custom-task.timer
. This timer will activate our service every 5 minutes.
sudo nano /etc/systemd/system/my-custom-task.timer
Add the following content to the file:
[Unit]
Description=Run My Custom Scheduled Task every 5 minutes
[Timer]
OnCalendar=*:0/5
Persistent=true
[Install]
WantedBy=timers.target
Save and exit the editor.
Explanation of OnCalendar
:
*:0/5
means "every 5 minutes".*
for year, month, day, hour (any value).0/5
for minute, meaning starting at minute 0, every 5 minutes (0, 5, 10, ..., 55).
In a typical systemd
environment, you would now run systemctl daemon-reload
to make systemd
aware of the new unit files, and then systemctl enable --now my-custom-task.timer
to start the timer.
Let's verify the existence of the created files:
ls -l /etc/systemd/system/my-custom-task.service
ls -l /etc/systemd/system/my-custom-task.timer
You should see output indicating that both files exist.
To simulate the execution of the service, you can manually run the command defined in ExecStart
:
sudo /bin/bash -c 'echo "My custom task executed at $(date)" >> /var/log/my-custom-task.log'
Now, check the log file to see the output:
sudo cat /var/log/my-custom-task.log
You should see the message you just logged:
My custom task executed at Tue Jun 10 06:54:40 UTC 2025
This completes the systemd timer configuration step. The service and timer unit files will remain in place for reference.
How to Manage Temporary Files with systemd-tmpfiles
Now you’ll learn how to manage temporary files and directories using systemd-tmpfiles
. This utility is part of systemd
and is responsible for creating, deleting, and cleaning up volatile and temporary files and directories. It's commonly used to manage /tmp
, /var/tmp
, and other temporary storage locations, ensuring that old files are removed periodically.
We will continue working on the local system to explore systemd-tmpfiles configuration.
You will need root privileges to configure systemd-tmpfiles
. Since the labex user has sudo access, we can use sudo
for the required commands.
systemd-tmpfiles
reads configuration files from /etc/tmpfiles.d/
and /usr/lib/tmpfiles.d/
. These files define rules for creating, deleting, and managing files and directories.
Let's create a custom configuration file to manage a new temporary directory. We will create a directory /run/my_temp_dir
and configure systemd-tmpfiles
to clean files older than 1 minute from it.
Create the configuration file /etc/tmpfiles.d/my_temp_dir.conf
:
sudo nano /etc/tmpfiles.d/my_temp_dir.conf
Add the following content to the file:
d /run/my_temp_dir 0755 labex labex 1m
Explanation of the line:
d
: Specifies that this entry defines a directory./run/my_temp_dir
: The path to the directory.0755
: The permissions for the directory.labex labex
: The owner and group for the directory.1m
: The age after which files in this directory should be deleted (1 minute).
Save and exit the editor (Ctrl+o
, Enter
, Ctrl+x
in nano
).
Now, let's tell systemd-tmpfiles
to apply this configuration. The --create
option will create the directory if it doesn't exist.
sudo systemd-tmpfiles --create /etc/tmpfiles.d/my_temp_dir.conf
Verify that the directory has been created with the correct permissions and ownership:
ls -ld /run/my_temp_dir
You should see output similar to:
drwxr-xr-x 2 labex labex 6 Jun 10 06:55 /run/my_temp_dir
Next, let's create a test file inside this new temporary directory:
sudo touch /run/my_temp_dir/test_file.txt
Verify the file exists:
ls -l /run/my_temp_dir/test_file.txt
Now, we need to wait for more than 1 minute for the file to become "old" according to our configuration. Wait for at least 70 seconds (1 minute and 10 seconds).
After waiting for more than 1 minute, we will manually run systemd-tmpfiles
with the --clean
option to trigger the cleanup process based on our configuration.
sudo systemd-tmpfiles --clean /etc/tmpfiles.d/my_temp_dir.conf
Finally, check if the test_file.txt
has been removed:
ls -l /run/my_temp_dir/test_file.txt
You should get a "No such file or directory" error, indicating that systemd-tmpfiles
successfully cleaned up the old file.
This completes configuring the systemd-tmpfiles. The configuration file and temporary directory will remain in place for reference.
Summary
In this tutorial, you learned how to schedule and manage one-time tasks using the at
command, including scheduling jobs interactively and non-interactively, viewing the at
queue with atq
, and deleting pending jobs with atrm
. You also learned how to schedule recurring user-specific tasks using crontab
, including how to edit, list, and remove cron jobs, and you learned the cron syntax for specifying execution times.
We also demonstrated how to schedule system-wide recurring tasks by placing scripts in standard cron directories (/etc/cron.hourly
, /etc/cron.daily
, etc.) and how to create custom cron jobs in /etc/cron.d
.
Finally, you explored advanced task scheduling with systemd
timers, learning to create and enable service and timer units for recurring tasks, and how to manage temporary files and directories using systemd-tmpfiles
for automated cleanup.
This comprehensive tutorial provided practical experience in managing diverse task scheduling needs on RHEL systems, from simple one-off commands to complex recurring system processes.
To practice the operations from this tutorial, try the interactive hands-on lab: Schedule Tasks in Red Hat Enterprise Linux.