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


12 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)