Many developers encounter issues when trying to run cron jobs under specific user accounts. The error "command not found" typically indicates the cron environment isn't properly loading the user's PATH and other environment variables.
When you add a cron job in /etc/cron.d/
with a user specification like this:
# /etc/cron.d/myjob
* * * * * user1 /path/to/script.sh
The script executes with user1's permissions but doesn't inherit the user's full environment (like ~/.bashrc
or ~/.profile
settings). This is different from running the script manually as the user.
Option 1: Using su -c with Full Login Shell
The most reliable method is to use su -l
to simulate a full login:
# /etc/cron.d/myjob
* * * * * root su -l user1 -c '/path/to/script.sh'
This ensures all environment variables from the user's profile are loaded.
Option 2: User's Personal Crontab
For user-specific jobs, it's often better to use the user's own crontab:
$ sudo -u user1 crontab -e
Then add the job directly:
# User user1's personal crontab
* * * * * /path/to/script.sh
Option 3: Explicitly Setting Environment
If you must use system crontab, explicitly set required environment variables:
# /etc/cron.d/myjob
SHELL=/bin/bash
PATH=/usr/local/sbin:/usr/local/bin:/sbin:/bin:/usr/sbin:/usr/bin
* * * * * user1 source ~user1/.profile && /path/to/script.sh
When debugging cron issues:
- Always use absolute paths in scripts
- Capture stdout/stderr to log files for debugging
- Test the environment by running
env > /tmp/cronenv.log
in your job - Consider using
#!/usr/bin/env bash
in scripts rather than direct paths
Here's a complete example implementing best practices:
# /etc/cron.d/backup_job
SHELL=/bin/bash
PATH=/usr/local/bin:/usr/bin:/bin
MAILTO=admin@example.com
30 2 * * * root su -l backup_user -c '/usr/local/bin/backup_script.sh >> /var/log/backup.log 2>&1'
This setup ensures:
- Full environment loading via
su -l
- Proper path settings
- Log capturing
- Email notifications on failures
When setting up a cron job to run under a specific user (e.g., user1
), you might encounter a "command not found" error even after specifying the user in /etc/cron.d
. This typically happens because the cron job doesn't inherit the user's environment variables, including the PATH
.
While /etc/cron.d
allows you to specify a user in the cron entry (e.g., user1
), the job still runs with a minimal environment. This means:
- The user's
.bashrc
or.profile
isn't sourced - Custom
PATH
settings aren't available - Environment variables specific to the user's session are missing
Method 1: Using crontab -e as the Target User
The most reliable way is to edit the user's personal crontab:
sudo -u user1 crontab -e
Then add your job (with full paths to commands):
0 3 * * * /usr/bin/python3 /home/user1/scripts/daily_task.py
Method 2: Using su -c in /etc/cron.d
If you must use /etc/cron.d
, wrap your command with su
:
0 3 * * * user1 /bin/bash -c "source /home/user1/.bashrc && /home/user1/scripts/daily_task.sh"
Method 3: Systemd Timers (Modern Alternative)
For newer systems, consider systemd timers:
[Unit]
Description=Daily task for user1
[Service]
Type=simple
User=user1
ExecStart=/home/user1/scripts/daily_task.sh
[Timer]
OnCalendar=daily
Persistent=true
[Install]
WantedBy=timers.target
To troubleshoot environment problems, create a test cron job that logs the environment:
*/5 * * * * user1 /bin/bash -c "env > /tmp/cron_env.log"
Then compare with the user's normal environment:
sudo -u user1 -i env > /tmp/user_env.log
- Always use absolute paths in cron jobs
- Explicitly source necessary environment files if needed
- Consider logging output for debugging
- For complex setups, use wrapper scripts that set up the environment
Create /home/user1/scripts/run_as_user.sh
:
#!/bin/bash
source /home/user1/.bashrc
export PATH=/usr/local/bin:$PATH
/home/user1/scripts/daily_task.sh >> /var/log/user1_cron.log 2>&1
Then call it from cron:
0 3 * * * user1 /bin/bash /home/user1/scripts/run_as_user.sh