A Bash script can work perfectly when you run it in a terminal and still fail when you schedule it. Sometimes the schedule is wrong. More often, the script depends on something your interactive shell provided without you noticing.
This tutorial shows how to run a Bash script with cron on Linux from beginning to end. You will build a harmless test script, schedule it to run every five minutes, capture its output, confirm that the scheduler executed it, and remove the test job without disturbing other scheduled tasks.
To run a Bash script with cron, first make sure the script works independently of your interactive terminal. Then open your user crontab with crontab -e and add an entry containing a schedule and the command that launches the script.
For example, the following user crontab entry runs a script every five minutes and appends its output to a log:
*/5 * * * * /bin/bash "$HOME/.sa-cron-practice/report.sh" >> "$HOME/.sa-cron-practice/report.log" 2>&1
This example assumes Bash is available at /bin/bash, the script exists, and the cron user’s HOME points to the expected directory. The full tutorial explains how to check these assumptions before installing the entry.
- What cron actually does when it starts a Bash script.
- How to prepare a script for unattended execution.
- How to schedule it using a user crontab.
- Why absolute paths and predictable environments matter.
- How to capture standard output and errors.
- How to verify that the job ran automatically.
- How to remove one test job safely.
- 🧠 Understand the Difference Between a Script and a Scheduler
- ⚙️ What Happens When Cron Starts Your Script?
- Execution Identity
- Execution Environment
- File Paths
- Observable Results
- ⏰ How the Five-Minute Cron Schedule Works
- 🧪 Mini Lab: Run a Bash Script with Cron in 7 Steps
- 🔍 Why a Script Can Work Manually but Fail Under Cron
- 📋 How to Check Whether Cron Actually Ran
- 🛡️ How to Make a Scheduled Bash Script More Reliable
- Use Predictable Paths
- Use the Right Account
- Control Dependencies
- Record Useful Results
- ⚠️ One Surprising Crontab Problem: The Percent Sign
- 🚫 Common Mistakes When Scheduling Bash Scripts
- 🧭 When Is Cron the Right Tool?
- 🧠 Knowledge Check
- 📚 Official References
🧠 Understand the Difference Between a Script and a Scheduler
A Bash script and a cron job are not the same thing.
A Bash script contains the work you want performed: checking a directory, generating a report, or running a maintenance command.
Cron decides when to launch that work.
The script can normally be executed without cron. Cron can execute commands that are not Bash scripts. The two components become useful together when you need repeatable work to happen without manually opening a terminal.
Cron schedules execution; it does not automatically verify that the work succeeded.
If the scheduling mechanism itself is new to you, start with Linux Cron Jobs Explained. That foundational lesson covers cron syntax, calendar matching, execution identity, and why scheduled commands can fail.
This tutorial focuses on the next practical task: installing and observing a real scheduled script.
⚙️ What Happens When Cron Starts Your Script?
A user crontab associates commands with a schedule. When a matching time arrives, the cron daemon launches the command as the user who owns that crontab.
This execution is separate from your interactive terminal session.
That distinction matters because the scheduled command may not receive the same environment variables, working directory, shell settings, or command search path that you used while testing.
Execution Identity
A command in your user crontab normally runs with your account’s identity and permissions, not automatically as root.
Execution Environment
Cron supplies its own execution environment. Your interactive aliases, shell customizations, and manually exported variables should not be assumed to exist.
File Paths
Relative paths depend on the process’s working directory. A script that silently assumes a particular directory may fail when scheduled.
Observable Results
Cron launching a command does not prove the command succeeded. Logging and verification provide evidence about what actually happened.
These are ordinary Linux process behaviors, not special defects in cron. The Linux Environment Variables Explained lesson shows why one process does not automatically inherit arbitrary settings from another terminal session.
⏰ How the Five-Minute Cron Schedule Works
A normal user crontab entry contains five scheduling fields followed by a command.
minute hour day-of-month month day-of-week command
For the practice job, we will use:
*/5 * * * *
The expression selects minute values divisible by five within each hour: minute 0, 5, 10, 15, and so on.
It does not mean “five minutes after the previous run finishes.” Cron matches clock times; it is not automatically an interval timer measured from task completion.
This distinction matters when jobs take several minutes to finish or when overlapping runs would cause problems.
🧪 Mini Lab: Run a Bash Script with Cron in 7 Steps
Create a small diagnostic script in your home directory, schedule it every five minutes, read its output, and remove the cron entry afterward.
The test script only prints diagnostic information. It does not install packages, modify server configuration, stop services, or require administrator privileges.
First, confirm that the required commands exist:
command -v bash
command -v crontab
On many Linux systems, Bash is installed at /bin/bash or /usr/bin/bash. Check the actual output rather than assuming one path is universal.
Next, inspect your existing user crontab:
crontab -l
If your account does not have a crontab yet, the command may report that no crontab is installed. That is not necessarily an error with the cron service.
Do not continue until Bash and the crontab command are available. A cron implementation must also be installed and running for scheduled jobs to execute.
We will keep the script and its log in a dedicated directory under your home directory.
mkdir -- "$HOME/.sa-cron-practice"
This deliberately uses mkdir without -p. If the directory already exists, the command fails instead of silently reusing a directory that may contain previous work.
If it already exists, inspect it and choose a different practice directory before proceeding. Do not overwrite unknown files.
A directory under your home is preferable to an arbitrary temporary directory for this experiment, because temporary storage may be cleaned automatically before the next scheduled execution.
Create a script that records the time, user, working directory, and a simple completion marker.
cat > "$HOME/.sa-cron-practice/report.sh" <<'EOF'
#!/usr/bin/env bash
set -u
printf 'time=%s\n' "$(date -Is)"
printf 'user=%s\n' "$(id -un)"
printf 'working_directory=%s\n' "$PWD"
printf 'result=ok\n'
EOF
The quoted 'EOF' marker is important. It prevents your current shell from expanding the script’s variables while the file is being created.
Make the script executable:
chmod u+x "$HOME/.sa-cron-practice/report.sh"
In this tutorial, we will explicitly launch the script with Bash. That makes the intended interpreter clear even if executable permissions or shebang handling differ in another environment.
If you are new to script files, the Bash Scripting Basics lesson explains shebangs, script execution, quoting, and exit statuses.
Before installing a cron job, verify that the script works when most interactive environment variables are absent.
env -i \
HOME="$HOME" \
PATH=/usr/bin:/bin \
/bin/bash "$HOME/.sa-cron-practice/report.sh"
If Bash is not located at /bin/bash on your system, replace that path with the one reported by command -v bash.
Example output:
time=2026-10-11T18:35:00+00:00
user=student
working_directory=/home/student
result=ok
The values on your server will differ.
This experiment does not reproduce every detail of a cron implementation. It checks whether the script depends unnecessarily on your interactive environment.
A script that fails this controlled test should be fixed before it is scheduled.
Open the current user’s crontab:
crontab -e
Add the following line at the end of the file:
*/5 * * * * /bin/bash "$HOME/.sa-cron-practice/report.sh" >> "$HOME/.sa-cron-practice/report.log" 2>&1
Again, substitute the correct Bash executable path if it differs on your system.
In common Linux cron implementations, HOME is initialized from the crontab owner’s account information. If you have overridden it in the crontab, adjust the paths so they refer to the practice directory you created.
Save and close the editor. Then verify that your entry was installed:
crontab -l
Your entry should appear alongside any existing jobs.
If the account already has scheduled tasks, preserve them. Do not paste an incomplete crontab over the existing schedule.
In particular, crontab -r removes the user’s crontab. It is not the command for removing one selected job.
Keep the test entry installed until at least one matching five-minute boundary has passed.
Then inspect the log:
tail -n 12 "$HOME/.sa-cron-practice/report.log"
A successful run should append diagnostic lines similar to those you saw during the manual test.
After another scheduled run, the file should contain another group of output lines with a new timestamp.
The logging portion of the cron entry is:
>> "$HOME/.sa-cron-practice/report.log" 2>&1
Here, >> appends standard output to the log file. The 2>&1 portion sends standard error to the same destination.
The order matters because shell redirections are processed in sequence.
If the log does not exist yet, do not immediately conclude that cron is broken. The next matching time may not have arrived, the daemon may not be running, or the command may have failed before opening the expected log.
Once you have verified at least one automatic run, remove the test entry so it does not continue generating log data indefinitely.
Open:
crontab -e
Delete only the line that launches .sa-cron-practice/report.sh. Leave any unrelated entries untouched.
Save the crontab, then check:
crontab -l
Confirm that the test entry is gone before removing its files.
Inspect the directory one final time:
ls -la "$HOME/.sa-cron-practice"
If it contains only the files created for this lab, remove those exact files and the now-empty directory:
rm -f -- \
"$HOME/.sa-cron-practice/report.sh" \
"$HOME/.sa-cron-practice/report.log"
rmdir -- "$HOME/.sa-cron-practice"
The rmdir command removes the directory only when it is empty. This is preferable to a recursive deletion command for a small controlled experiment.
🔍 Why a Script Can Work Manually but Fail Under Cron
Running a script successfully in a terminal is necessary evidence, but it is not a complete cron test.
Your interactive shell may have loaded startup configuration, modified PATH, activated a programming environment, or changed into a project directory.
Cron does not automatically reproduce all of those conditions.
| Symptom | Possible Cause | What to Check |
|---|---|---|
| Command not found | Different PATH |
Executable location and cron environment |
| File not found | Relative path or wrong working directory | Paths used inside the script |
| Permission denied | Wrong user or missing permissions | Owner, directory access, executable permissions |
| No output file | Job did not start or output path is invalid | Crontab, daemon, destination directory |
| Job starts but fails | Application or script error | Captured stderr, exit status, application logs |
| Two runs overlap | Previous execution is still active | Task duration and concurrency controls |
A useful troubleshooting habit is to investigate one layer at a time:
Was the job scheduled? Did cron launch it? Did Bash start the script? Did the script complete successfully?
These are four separate questions. A positive answer to one does not automatically establish the next.
📋 How to Check Whether Cron Actually Ran
Your script’s own log shows what the command wrote to standard output and standard error.
If that log is missing, you may also need evidence from the scheduler itself.
On a systemd-based Linux server, cron may be managed under a service name such as cron or crond, depending on the distribution and implementation.
Inspect the service that exists on your system:
systemctl status cron --no-pager
systemctl status crond --no-pager
One of these names may be absent. That does not by itself mean scheduling is unavailable; it may simply mean your distribution uses the other name or a different service manager.
If your system records cron messages in the systemd journal, inspect the relevant service’s messages:
journalctl -u cron.service -b -n 30 --no-pager
Change the unit name if your cron daemon uses a different service.
Journal access depends on local permissions and logging configuration. Some systems record cron activity through syslog or a separate log file instead.
The important distinction is between a scheduler record and the application’s result.
A message showing that cron started a command is not proof that the script successfully completed its work.
For more detail, see journalctl Explained: How to Read Linux Service Logs and Find Errors.
🛡️ How to Make a Scheduled Bash Script More Reliable
The practice script is intentionally small. Real server automation needs a little more preparation.
Use Predictable Paths
Resolve the files and directories your job needs explicitly. Do not assume cron starts the script from the directory you used during manual testing.
Use the Right Account
Schedule work under an account with the permissions it actually requires. Avoid using root simply to bypass a permissions problem.
Control Dependencies
Verify that Bash, external commands, and application configuration are available in the scheduled execution context.
Record Useful Results
Produce meaningful error messages and exit statuses. A task that runs silently but never produces the expected result is difficult to troubleshoot.
For production maintenance jobs, decide how logs will be retained and rotated. A file opened in append mode can continue growing every time the job runs.
Also consider the job’s duration. Cron can launch a new instance at the next matching time even when the previous instance has not finished. Jobs that modify shared state may require appropriate locking or a different execution model.
If you need dependencies, managed service state, or stronger journal integration, compare the design with Cron vs systemd Timers.
⚠️ One Surprising Crontab Problem: The Percent Sign
Traditional cron syntax assigns special meaning to the percent character % inside the command portion of a crontab entry.
An unescaped percent sign may be converted into a newline and affect what is sent to the command’s standard input.
This often surprises administrators who put commands such as date with formatting expressions directly into their crontab.
The safer approach for a beginner is to keep nontrivial shell logic inside a separate script, as we did in this tutorial.
Notice that our script uses date -Is, and the formatting logic lives inside the script rather than inside the crontab entry.
Cron parses a crontab entry before launching its command. Bash then interprets the command it receives. Keeping complex work in a script makes these two layers easier to reason about.
🚫 Common Mistakes When Scheduling Bash Scripts
Most early cron problems come from assumptions about execution rather than errors in the five schedule fields.
- Using an incorrect Bash path. Check the interpreter installed on your server rather than copying a path blindly.
- Scheduling before testing. A script should run successfully on demand before cron is introduced.
- Depending on interactive shell settings. Cron does not automatically load the same environment as your interactive terminal.
- Using relative paths unintentionally. A different working directory can change which files a command reads or writes.
- Ignoring standard error. The absence of visible output does not mean the scheduled command succeeded.
- Confusing execution with success. Cron can launch a command that exits unsuccessfully or produces an incomplete result.
-
Removing the whole crontab.
Delete the intended job through
crontab -e; do not erase unrelated scheduled tasks.
🧭 When Is Cron the Right Tool?
Cron works well for straightforward recurring commands whose behavior is already predictable.
It is a practical choice for tasks such as generating a report, inspecting an application directory, or running a maintenance script at a known time.
Cron may be less convenient when a workload requires complex dependencies, persistent service management, sophisticated retry behavior, or an elapsed-time interval rather than calendar matching.
If the machine is powered off when the schedule matches, an ordinary cron job generally does not automatically replay that missed execution when the machine starts again. The specific behavior can differ when other scheduling tools or extensions are involved.
The goal is not to use the most advanced scheduler available. It is to choose the simplest mechanism that makes the required behavior clear and verifiable.
🧠 Knowledge Check
These questions test whether you understand the execution model rather than simply remember the commands.
1. Does a successful manual script run prove cron will execute it successfully?
No. Manual execution proves the script worked in that terminal’s context. Cron may supply a different environment, working directory, or execution identity.
2. What does */5 mean in the minute field?
It selects every fifth minute within each hour. It does not mean five minutes after the previous execution finishes.
3. Why does the example redirect both stdout and stderr?
Standard output records normal messages, while standard error can contain diagnostic messages. Capturing both makes the unattended command easier to investigate.
4. Why do we test the script with env -i?
It launches the script with a deliberately limited environment. This helps reveal dependencies on variables or shell configuration that may not be available when cron starts the script.
5. Does a cron service log entry prove a backup completed?
No. A scheduler log can indicate that a command was launched. Successful completion requires separate evidence, such as a checked exit status, application output, or a verified backup artifact.
6. Why should you remove only the test entry from crontab?
A user’s crontab may contain unrelated production tasks. Removing the entire crontab could unintentionally disable those jobs.
To run a Bash script with cron reliably, treat scheduling and script execution as separate parts of one workflow.
First make the script work independently. Then schedule it under the intended user, make its paths predictable, capture useful output, and verify an actual scheduled execution.
The central lesson is that an installed cron entry is not the same as a successful automated task. Reliable automation requires evidence that the command started and that the work it was supposed to perform actually completed.
📚 Official References
These primary sources document cron scheduling, crontab behavior, and Linux process execution.
- Cronie — crontab(5) — crontab format, environment settings, scheduling fields, and special characters.
- Cronie — crontab(1) — installing, editing, listing, and removing user crontabs.
- Debian — crontab(5) — Debian cron behavior and configuration examples.
- GNU Bash Manual — Redirections — standard output, standard error, and redirection order.








