When moving commands from interactive shell to cron, special characters like double quotes and percent signs often cause unexpected failures. The fundamental reason lies in how cron handles command interpretation versus bash shell processing.
Here's the original working command that fails in cron:
grep abc /var/log/messages | grep "`date '+%B %d'`" | mail -s"abc log of `hostname`" s.o+`hostname`@gmail.com
Three specific elements cause issues in cron:
1. Nested double quotes around date command
2. Percent signs in date format (%B %d)
3. Command substitution backticks
The safest approach is to:
1. Replace backticks with $( ) syntax
2. Escape percent signs with backslashes
3. Use single quotes for outer wrapping
Here's the properly escaped version for crontab:
grep abc /var/log/messages | grep "$(date '+\%B \%d')" | mail -s"abc log of $(hostname)" "s.o+$(hostname)@gmail.com"
For complex commands, consider these approaches:
# Method 1: Wrap in a bash script
#!/bin/bash
grep abc /var/log/messages | grep "$(date '+%B %d')" | mail -s"abc log of $(hostname)" "s.o+$(hostname)@gmail.com"
# Method 2: Use environment variables
DATE_STR=$(date '+%B %d')
HOST_STR=$(hostname)
grep abc /var/log/messages | grep "$DATE_STR" | mail -s"abc log of $HOST_STR" "s.o+$HOST_STR@gmail.com"
- Always test commands in the same environment cron uses:
env -i /bin/sh -c "your_command"
- For complex commands, use scripts instead of inline cron commands
- Capture output and errors with proper redirection
I recently encountered an annoying issue where a perfectly working bash command failed when moved to crontab. The command involved grep operations with date formatting and email notifications. Here's the original command that worked in terminal:
grep abc /var/log/messages | grep "`date '+%B %d'`" | mail -s"abc log of `hostname`" s.o+`hostname`@gmail.com
Cron uses its own special character handling rules that differ from the bash shell. The main culprits in my case were:
- Double quotes ("") needing special escaping
- Percent signs (%) being interpreted as newlines
- Backticks (`) requiring alternative command substitution syntax
After several iterations, here's the version that works in crontab:
0 9 * * * /bin/bash -c 'grep abc /var/log/messages | grep "$(date \"+\%B \%d\")" | mail -s"abc log of $(hostname)" "s.o+$(hostname)@gmail.com"'
1. Percent Sign Escaping: All % signs must be escaped as \%
2. Command Substitution: Replaced backticks with $( ) syntax
3. Double Quote Handling: Used escaped quotes \" for date format
4. Explicit Bash Invocation: Called /bin/bash with -c flag
Another clean solution is to move the logic to a script file:
#!/bin/bash
log_entry="abc"
log_file="/var/log/messages"
current_date=$(date "+%B %d")
email_subject="abc log of $(hostname)"
email_to="s.o+$(hostname)@gmail.com"
grep "$log_entry" "$log_file" | grep "$current_date" | mail -s"$email_subject" "$email_to"
Then call this script from crontab without special character concerns:
0 9 * * * /path/to/script.sh
- Forgetting to escape % signs in date formats
- Using backticks instead of $( ) syntax
- Missing proper quoting of variables and strings
- Assuming cron has the same environment as your shell
When troubleshooting cron issues:
# Check cron logs
sudo tail -f /var/log/syslog | grep CRON
# Capture output and errors
0 9 * * * /path/to/command > /tmp/cron_debug.log 2>&1