October DealsAmazon USOctober deal check: compare before you payAmazon US: current deals, useful picks and tech finds.Check DealsSlow PC?RecommendedPC slow today? Run a repair scan before it gets worseResolve common Windows issues and optimize system performance.Scan NowOctober DealsAmazon USDeal season is back - check today's better picksAmazon US: current deals, useful picks and tech finds.See Picks×
Skip to content
World desk11 min

Why Your Cron Job Isn’t Running Your Shell Script (and How to Fix It)

Cron runs with a different shell, environment, directory, and user than your terminal. This guide shows how to prove the daemon fired, make Bash and paths explicit, capture errors, and fix permission and logging failures.
Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.

If a shell script works in your terminal but fails from cron, the scheduler is usually not seeing the same shell, environment, working directory, user, or permissions. Make those assumptions explicit: name Bash, use absolute paths, set a known PATH, redirect both output streams, and verify the daemon and the crontab that actually contains the job.

A dependable per-user entry looks like this:

SHELL=/bin/bash
PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin
* * * * * /usr/bin/env bash /home/alice/bin/backup.sh >>/home/alice/log/backup.cron.log 2>&1

Why a script works manually but not from cron

A terminal session is interactive. It loads shell startup files, starts in a directory you recognize, supplies your usual PATH, and runs as the account you expect. Cron launches a command non-interactively with a small, defined environment. It does not reliably inherit the settings your interactive shell assembled.

As an Amazon Associate I earn from qualifying purchases.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.

That difference creates several common failures:

  • The default command interpreter is /bin/sh, not necessarily Bash. Bash-only syntax such as arrays, [[ ... ]], process substitution, or set -o pipefail can fail before the script does useful work.
  • A command found through your terminal’s PATH cannot be found by cron’s shorter PATH.
  • A relative filename resolves from a different working directory, so an input file, configuration file, or log path is missing.
  • The job runs as the crontab owner, or as the explicit account in a system-wide cron file. That account may not be able to traverse a directory, read a secret, open a socket, or write a log.
  • Output is mailed or sent to a system log rather than displayed in your terminal. Without redirection, an apparent “silent” failure can be hard to see.

Cron examines its stored crontabs and checks each job for the current minute, as described by the crond(8) manual. Your first task is therefore to prove whether the scheduler fired; only then should you debug the script’s application logic.

Use the right crontab format

Before changing a command, confirm where it is installed. The syntax differs between a personal crontab and system-wide files.

Location How to edit or inspect Fields on a job line Account used
Per-user crontab crontab -e or crontab -l as that user Minute, hour, day of month, month, day of week, command The owner of that crontab
/etc/crontab Edit as root; inspect directly The five schedule fields, then a username, then the command The username on the line
/etc/cron.d/<file> Edit as root; inspect the specific file The five schedule fields, then a username, then the command The username on the line

Do not copy the username field into a per-user crontab. Conversely, omitting it from /etc/crontab or a file under /etc/cron.d shifts every field and prevents the intended command from running.

A reliable cron entry

Put the following in the intended user’s crontab with crontab -e:

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.
SHELL=/bin/bash
PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin
MAILTO=
* * * * * /usr/bin/env bash /home/alice/bin/backup.sh >>/home/alice/log/backup.cron.log 2>&1

The one-minute schedule is for testing; replace it with the real schedule after the job is proven. MAILTO= suppresses cron mail, so use it only when the log is monitored. If you want mail instead, set [email protected] and still keep a durable log while troubleshooting.

For a system file, include the account:

SHELL=/bin/bash
PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin
* * * * * alice /usr/bin/env bash /home/alice/bin/backup.sh >>/home/alice/log/backup.cron.log 2>&1

Ensure the log directory already exists and is writable by the effective account. Cron will not create missing parent directories for a redirection.

Step-by-step diagnosis

1. Confirm the schedule and account

  1. Run whoami to identify the account you intend to use.
  2. Run crontab -l as that account. If you used sudo crontab -e, you edited root’s crontab instead.
  3. Check system locations if the job is supposed to be global: /etc/crontab, /etc/cron.d, and the distribution’s other cron directories.
  4. Check every schedule field for accidental punctuation, an invalid range, or a missing field. Save the file through crontab -e so the cron implementation validates it when installing.

A schedule can be perfectly valid yet appear inactive if it was saved under another account. Always inspect the exact crontab that owns the process.

2. Prove that the daemon is running

Most Linux distributions call the service cron or crond. Check the name used by your distribution:

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.
systemctl status cron
systemctl status crond

Use the command that returns a real service on your system. If it is stopped, start it and enable it according to your operating system’s service policy. Then inspect recent service messages:

journalctl -u cron --since "15 minutes ago"
journalctl -u crond --since "15 minutes ago"

On systems that do not use the systemd journal, cron messages may be in a syslog file such as /var/log/cron or /var/log/syslog. File names and facilities are distribution-specific; search for the job’s command, account, or the word CRON.

3. Use a harmless one-minute test

Temporarily replace the real command with a test that has no application dependencies:

* * * * * /usr/bin/touch /home/alice/cron-ran

After the next minute, check the file’s timestamp and ownership. If it appears, the scheduler is firing and the account can write there. If it does not, concentrate on the daemon, crontab location, schedule syntax, filesystem permissions, or service logs rather than the shell script.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.

Choose a path whose parent directories already exist and are traversable by the cron account. A test in a private directory can fail for permission reasons even when cron itself is healthy.

4. Select the intended shell

The crontab(5) manual documents that SHELL defaults to /bin/sh. A script that begins with a Bash shebang should still be invoked unambiguously while you diagnose it:

#!/usr/bin/env bash
set -euo pipefail

Then call it from cron with:

/usr/bin/env bash /home/alice/bin/backup.sh

Alternatively, set SHELL=/bin/bash in the crontab. Explicit invocation is clearer when a line contains shell operators, command substitutions, or redirections. Check that the interpreter exists at the path you selected; minimal systems may place it elsewhere.

5. Make the environment explicit

Cron commonly supplies variables such as SHELL, PATH, USER, LOGNAME, HOME, and LANG, but their values are not a substitute for application configuration. Define every variable the script needs in the script, an environment file that the script reads explicitly, or the crontab.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.

Do not assume that a crontab assignment performs interactive-shell expansion. The manual states: “The value string is not parsed for environmental substitutions or replacement of variables.” Thus this is unsafe:

PATH=$HOME/bin:$PATH

Use a literal value instead:

PATH=/home/alice/bin:/usr/local/bin:/usr/bin:/bin

For diagnosis, add a temporary environment dump:

* * * * * /usr/bin/env >/home/alice/log/cron-environment.txt 2>&1

Remove it after inspecting the file because environment dumps can expose credentials or tokens. Do not rely on aliases, shell functions, interactive prompts, terminal settings, or startup files such as .bashrc being loaded.

6. Replace every relative path

Use absolute paths for the interpreter, executable commands, configuration files, inputs, outputs, and logs. A command that works as rsync in a terminal may need to be /usr/bin/rsync under cron. Find a command’s location interactively with command -v rsync, then use the resulting path after verifying it is stable on that host.

If the program expects to run from a project directory, change directory explicitly and fail if that operation fails:

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.
cd /home/alice/app || exit 1
/usr/bin/python3 /home/alice/app/job.py

Do not assume that HOME points to a particular account or that the scheduler starts in your project directory. A relative redirect such as >>logs/job.log can fail before the script starts if logs is not beneath the current directory.

7. Check identity and permissions

Test the job as the same account cron uses. Confirm all of the following:

  • The account can execute the script, or the command invokes the interpreter directly and can read the script.
  • It can traverse every parent directory. Directory search permission is required even when the final file is readable.
  • It can read input files and configuration, create or append the log, and write the destination directory.
  • Credentials, SSH keys, database sockets, mounts, and service endpoints are available to that account at the scheduled time.
  • Mandatory access controls, container boundaries, or network policies are not denying the operation.

Inspect ownership and modes with ls -ld on every parent directory and ls -l on the files. Avoid solving a cron failure by making secrets or entire directory trees world-writable; grant the narrow permission the job needs.

8. Capture stdout and stderr

Always redirect both streams while troubleshooting:

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.
>>/home/alice/log/backup.cron.log 2>&1

The first operator appends standard output; 2>&1 sends standard error to the same file. Put the redirection on the cron command, not only inside a script branch that may never execute. Use a separate absolute log for each job when multiple schedules would otherwise interleave messages.

Cron normally mails command output to the owner or to the address in MAILTO, and some implementations also send events to syslog. Check local mail for the account and the cron or syslog files. On a systemd-cron implementation, inspect the generated unit and its journal entries because the generated service is the authoritative execution record.

9. Separate scheduler failure from script failure

Once the touch test proves scheduling, restore the script with logging and run the same command manually as the cron account. Compare the environments rather than comparing it with your normal desktop session:

sudo -u alice /usr/bin/env -i 
  HOME=/home/alice 
  PATH=/usr/local/bin:/usr/bin:/bin 
  /usr/bin/env bash /home/alice/bin/backup.sh

Adjust the account and paths for your host. This approximates cron’s sparse environment and often exposes an undeclared variable or missing executable.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.

For a Bash script, temporary tracing can show the command that fails:

set -euxo pipefail

Use this only when the script is compatible with those options. Tracing can print secrets and can change behavior in scripts that intentionally handle nonzero statuses, so remove or narrow it after diagnosis. The log and process exit status, not the absence of an error message in your terminal, determine whether the run succeeded.

10. Check systemd-cron and duplicate daemons

Some systems provide cron behavior through systemd-generated units. In that case, inspect the generated unit and its journal entry to see the exact command, account, exit status, and captured output. A traditional cron daemon and a systemd-based implementation should not both be active for the same schedules; two daemons can run a job twice, making a missed run look intermittent or producing duplicate side effects.

Independent reader supportYour contribution helps us test, update, and keep practical guides available for everyone.Support on Ko-Fi

Common symptoms and precise fixes

Symptom Likely cause What to check
bash: syntax error or an unexplained parse failure The command was interpreted by /bin/sh Use a Bash shebang and invoke /usr/bin/env bash, or set SHELL=/bin/bash.
command not found Cron’s PATH does not include the executable Use its absolute path and define a literal, safe PATH.
Input or configuration file is “missing” A relative path resolved from another directory Use absolute paths and cd explicitly with an error check.
No log file is created The parent directory is absent or not writable Create it ahead of time and test write permission as the cron account.
The job never appears in logs Wrong crontab, invalid system-file format, or stopped daemon Run crontab -l as the intended user, verify the username field in system files, and check cron/crond status.
The job runs twice Duplicate entries or two cron implementations Search all crontabs and system locations, then ensure only the intended daemon handles the schedule.
The script works manually but cannot reach a service Different user, credentials, mount, socket, or environment Run it as the cron account with an explicit environment and verify the resource is available at run time.

Writing a cron-safe shell script

A script should fail loudly, identify its working directory, and make its dependencies visible. For example:

Free tools Windows power users keep installed

One-click scans. No signup required.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.
#!/usr/bin/env bash
set -euo pipefail

PATH=/usr/local/bin:/usr/bin:/bin
export PATH

cd /home/alice/app || {
  printf '%sn' 'Cannot enter /home/alice/app' >&2
  exit 1
}

/usr/bin/rsync -a --delete 
  /home/alice/app/data/ 
  /home/alice/backups/data/

The script sets its own PATH, changes to a known directory, uses an absolute executable path, and sends a clear error to standard error. The cron entry remains responsible for capturing that error in a durable log.

Be deliberate with concurrency. If a schedule can start again before a previous run finishes, protect the operation with an appropriate lock or an atomic application-level mechanism. Do not add a lock blindly: choose behavior for stale locks, failed runs, and overlapping work, and record those outcomes in the log.

Choosing classic cron or a systemd timer

For a simple, independent command, cron can be sufficient. A systemd timer may be a better fit when the job’s lifecycle is already managed by systemd, but the right choice depends on the host and operational requirements. Compare the implementations on these axes before migrating:

Requirement Questions to answer
Dependency ordering Must the job wait for a mount, network target, or another service?
Environment and user isolation Where are the account, working directory, environment, and permissions declared?
Persistence after downtime Should a missed run be caught up when the machine returns, or simply skipped?
Logging Will operators inspect cron mail/syslog, a file, or the systemd journal?
Retry behavior What should happen after a nonzero exit status, and where is that policy configured?
Calendar expressiveness Can the schedule express the required calendar without hidden edge cases?
Duplicate-run protection How will overlapping executions be prevented and diagnosed?

Do not run both mechanisms for one schedule unless duplicate execution is intentional and controlled. Whichever scheduler you choose, retain absolute paths, explicit identity, captured output, and a health check that proves the command actually completed.

What’s actually slowing this PC down?

Pick the symptom - the matching free tool is one click away.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.

A practical verification checklist

  • Source: The entry is in the intended user’s crontab or has the required username field in a system file.
  • Schedule: A one-minute test has been observed at the expected path.
  • Daemon: The correct cron or crond service is active and its logs show the job being considered.
  • Interpreter: Bash is selected explicitly when the script uses Bash syntax.
  • Environment: PATH and application variables are literal and declared; no interactive startup file is required.
  • Paths: Every command, file, directory, and log path is absolute, or the script performs a checked cd.
  • Identity: The effective account can execute, read, traverse, write, and connect to every required resource.
  • Evidence: Standard output and standard error are redirected, and cron mail, syslog, or the systemd journal has been checked.
  • Exit status: The log proves success or records the failing command; a missing terminal message is not treated as success.

Once these checks pass, restore the intended schedule and remove temporary environment dumps, tracing, and one-minute test commands. Keep the explicit interpreter, paths, permissions, and logging in the production entry so the next failure produces evidence instead of guesswork.

Product prices and availability are accurate as of the date/time indicated and are subject to change. Any price and availability information displayed on Amazon at the time of purchase will apply.

Leave a Reply

Your email address will not be published. Required fields are marked *

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.

More from the Wire

  1. World desk4 min
    How to Spot an AI Voice Scam Before Sending MoneyDon’t rely on how a caller sounds. Pause, call back through a known number, and verify the emergency with another trusted person before sending money.
  2. Mountain View desk4 min
    Google’s SynthID Detector: How to Check AI-Generated Images, Video and AudioGoogle’s SynthID Detector looks for an embedded watermark in supported images, video and audio. Here is what its results do—and do not—show.
  3. Redmond desk20 min
    How to create a link to File or Folder in Windows 11Windows 11 gives you several ways to point to a file or folder without moving or duplicating it. You can create a desktop shortcut,…
Recommended PC Tool
Recommended PC Tool
Crashes, No Sound, or Screen Glitches?Free driver scan
Windows Errors? Fix Them Before They SpreadFree repair scan

Two free Windows tools

One Free Minute Could Fix That PC

Before you go - each of these free tools takes about a minute and tackles what quietly slows a Windows PC down.

Special offer. View Outbyte info, uninstall instructions, EULA, and Privacy Policy.