Understanding Cron’s Default Shell: How to Specify and Change the Shell for Crontab Commands


3 views

When working with cron jobs, many developers don't realize that cron doesn't automatically use their preferred interactive shell (like bash or zsh). The system uses a minimal shell environment by default, which can lead to unexpected behavior when your crontab contains complex commands or shell-specific syntax.

Most Unix-like systems configure cron to use /bin/sh as the default shell. This is typically a minimal POSIX-compliant shell, often linked to dash on modern Linux systems:


$ ls -l /bin/sh
lrwxrwxrwx 1 root root 4 Apr  5  2022 /bin/sh -> dash

Consider these common problems that arise:


# In crontab - this will fail if using default /bin/sh
*/5 * * * * echo "Current path: $PATH" > /tmp/cron_test.log

# Array syntax that works in bash/zsh but not in sh
0 * * * * declare -a arr=("a" "b"); for i in "${arr[@]}"; do echo $i; done

You have several approaches to control the shell environment:

1. SHELL Variable in Crontab


SHELL=/bin/bash
PATH=/usr/local/sbin:/usr/local/bin:/sbin:/bin:/usr/sbin:/usr/bin

* * * * * /path/to/your/command

2. Wrapping Commands in Your Preferred Shell


0 3 * * * /bin/bash -c 'source ~/.bashrc; your_command'

3. System-wide Configuration (Advanced)

On some systems, you can modify /etc/default/cron or equivalent:


# For Debian/Ubuntu systems
CRON_USE_UTC=no
CRON_SHELL=/bin/bash
  • Always use absolute paths to binaries
  • Set critical environment variables explicitly
  • Consider putting complex logic in separate scripts
  • Test commands directly with /bin/sh -c "your command"

Create a test cron job to capture the environment:


* * * * * /bin/bash -c 'env > /tmp/cron_env.log; type bash > /tmp/cron_type.log'

This will help you understand exactly what environment your cron jobs execute in.


Cron executes commands using a minimal environment that typically defaults to /bin/sh, which on most modern Linux systems is a symlink to either bash or dash. The exact shell used depends on your system configuration.

You can verify which shell your cron uses with:

ls -l /bin/sh
# Common output:
# lrwxrwxrwx 1 root root 4 Apr  5  2022 /bin/sh -> bash

The shell used by cron is typically defined in the crond configuration. For systemd-based systems:

cat /etc/default/cron
# Look for SHELL= parameter

Consider these examples of shell differences:

# bash/zsh array syntax
arr=(1 2 3)
echo ${arr[1]}  # bash: 2, zsh: 1 (different index base)

# Process substitution
diff <(echo foo) <(echo bar) # Works in bash, may fail in /bin/sh

1. Always specify full paths to binaries
2. For complex commands, use a script with proper shebang
3. Set environment variables explicitly in crontab

# Example crontab with explicit settings
SHELL=/bin/bash
PATH=/usr/local/sbin:/usr/local/bin:/sbin:/bin:/usr/sbin:/usr/bin

* * * * * /path/to/script.sh

To debug cron jobs:

# Redirect output to examine errors
* * * * * /path/to/command > /tmp/cron.log 2>&1

# Test command with minimal environment
env -i /bin/sh -c "your_command"

Some cron implementations (like Vixie cron) allow per-user shells:

# In /etc/crontab or user crontab
SHELL=/bin/zsh
* * * * * user command
  • Debian/Ubuntu: Defaults to dash (/bin/sh)
  • RHEL/CentOS: Defaults to bash (/bin/sh)
  • FreeBSD: Uses /bin/sh (ash-based)
  • MacOS: Uses /bin/sh (bash v3 for compatibility)