When running scripts through cron, you immediately encounter a fundamental difference from interactive shell sessions - cron jobs execute in a minimal environment without loading your normal shell initialization files like .bashrc
or .bash_profile
. This becomes particularly problematic when your scripts depend on environment variables defined in these files.
The two solutions you've considered each have significant drawbacks:
# Approach 1: Inline sourcing in crontab
* * * * * /bin/bash -c '. /home/user/env && /path/to/script'
# Approach 2: Source in every script
#!/bin/bash
source ~/user.env
# rest of script
The first approach makes your crontab messy and harder to maintain. The second creates duplication and makes it difficult to change environment variable locations later.
Option 1: Centralized Environment Loader
Create a dedicated environment loader script that all your cron jobs can use:
#!/bin/bash
# /usr/local/bin/load_env.sh
# Fail immediately if env file is missing
ENV_FILE="${HOME}/$(whoami).env"
if [ ! -f "${ENV_FILE}" ]; then
echo "Error: Environment file ${ENV_FILE} not found" >&2
exit 1
fi
# Source the environment file
set -o allexport
source "${ENV_FILE}"
set +o allexport
Then in your crontab:
* * * * * /usr/local/bin/load_env.sh && /path/to/your/script.sh
Option 2: System-wide Environment File
For server applications, consider using /etc/environment
(on systemd systems):
# /etc/environment
JAVA_HOME=/usr/lib/jvm/java-11-openjdk
APP_HOME=/opt/myapp
These variables will be available to all processes, including cron jobs.
Option 3: Wrapper Script Solution
Create a wrapper that maintains your environment:
#!/bin/bash
# /usr/local/bin/run_with_env
if [ $# -lt 1 ]; then
echo "Usage: $0 command [args...]" >&2
exit 1
fi
# Load environment
source "${HOME}/$(whoami).env"
# Execute command with original arguments
exec "$@"
Crontab entry:
* * * * * /usr/local/bin/run_with_env /path/to/your/script.sh param1 param2
For Java server apps specifically, you might want to:
- Set
JAVA_HOME
explicitly in your environment file - Include JVM options like memory settings
- Handle logging directory paths
Example environment file for Java:
# ~/java_app.env
export JAVA_HOME=/usr/lib/jvm/java-11-openjdk-amd64
export PATH="${JAVA_HOME}/bin:${PATH}"
export APP_OPTS="-Xmx2G -Xms1G -Dlog.dir=/var/log/myapp"
When running Java server applications through cron jobs, we often face environment variable loading issues because cron executes commands in a minimal environment. Unlike interactive shell sessions that load .bashrc
or .bash_profile
, cron jobs don't inherit these user-specific configurations.
While you could add source ~/user.env
at the beginning of every script, this creates maintenance headaches:
# Bad practice: Hardcoding paths in multiple scripts
source /home/myuser/myuser.env
# Rest of script logic...
This approach violates the DRY principle and makes environment management fragile across different deployment environments.
1. Centralized Environment Wrapper
Create a wrapper script that handles environment loading:
#!/bin/bash
# /usr/local/bin/run_with_env
set -e
source "${HOME}/${USER}.env"
exec "$@"
Then in crontab:
* * * * 1-5 /usr/local/bin/run_with_env /home/myuser/scripts/myscript.sh
2. Systemd Service Units (Modern Linux)
For long-running Java services, consider systemd:
# /etc/systemd/system/myservice.service
[Unit]
Description=My Java Service
[Service]
User=myuser
EnvironmentFile=/home/myuser/myuser.env
ExecStart=/home/myuser/scripts/myscript.sh
Restart=on-failure
[Install]
WantedBy=multi-user.target
3. Environment Directory Pattern
Create an env.d directory for modular configuration:
# In your script:
for f in ~/env.d/*.env; do
[[ -f "$f" ]] && source "$f"
done
For different environments (dev/stage/prod), use symbolic links:
ln -sf /etc/myapp/env/prod.env /home/deploy/.deploy.env
# Then source ~/.deploy.env in scripts
Always:
- Set proper permissions on env files (600)
- Never source files from world-writable directories
- Consider using /etc/environment for system-wide vars
Capture the actual environment:
* * * * * /usr/bin/env > /tmp/cronenv.log 2>&1