A common way to log crontab errors looks like below:

1 */8 * * * sh /pseudo_path/test.sh 2>> my_err_log 

It's a concise command, but it can't record the error occurred time, and the path of script file is omitted.

So I wrote an error record function:

PROGNAME=$(readlink -f "$0")

    timestamp="$(date +%Y%m%d-%H:%M:%S)"
    x_info=$(echo "Error_${PROGNAME}:Line_${1:-"null"}_")
    echo "$zeta" >> $SCRIPT_ERR_LOG_PATH
    exit 1

This function can log the time the error occurred, together with the absolute path of the script. But the downside is that I have to add || error_exit $LINENO at every line of my script to make it work. With Vim's bulk substitution it could be much easier, but it still looks like a clumsy solution.

So, is there a smarter or more efficient way to do the same task?

  • 1
    I would look at redirecting stderr only into a program that adds the timestamp to the line once it receives input. Given the commandline syntax for that is difficult to get right, it is in general easier to make a program that starts the sh /pseudo_path/test.sh that receives stderr and stdout separately and adds timestamps to the lines from stderr and writes them to file, but passes on stdout transparently. Python's subprocess.Popen() combined with .communicate() e.g. works well.
    – Anthon
    Jul 30, 2015 at 5:07

2 Answers 2


It looks to me like you're creating a Bash script, so take advantage of Bash's trap builtin. For example:

# vim: ft=sh:tw=75:fo-=t:fo+=rcq:ai:

function error_trap()
    local -ir __exit_code__=${1:-$?}
    local __timestamp__

    # Reset the ERR sigspec to its original disposition.
    trap - ERR

    __timestamp__=$( date --rfc-3339=seconds --date=now )

    # Hint...
    #declare -p BASH_LINENO
    #declare -p BASH_COMMAND

    echo "[${__timestamp__}] (Line: ${BASH_LINENO[0]}) :: ERROR :: ${BASH_COMMAND}" >&2

    exit ${__exit_code__}

# Register function 'error_trap' as the trap handler for
# the ERR (error) sigspec.
trap "{ error_trap; }" ERR

# Try it out; deliberately crash-and-burn this script.
ls this-does-not-exist

Here's the output I see when I invoke this script:

ls: cannot access this-does-not-exist: No such file or directory
[2015-07-30 01:36:32-05:00] (Line: 24) :: ERROR :: ls this-does-not-exist

Depending on the quantity of the logging information you're expecting to produce, it might be worth using the standard logger tool to write it to the user syslog in /var/log:

1 */8 * * * /path/to/myprog 2>&1 | logger -p user.debug -t 'myprog'

Here is an example of the output written to /var/log/debug on my Debian-based system:

Jul 31 00:17:09 myserver myprog: test message with user.debug

There are various facility/level pairs available for use. You might want to consider user.notice or user.info or user.debug. Just be aware that some of these may also get written to /var/log/messages and /var/log/syslog.

If you want to differentiate stdout and stderr in your cron job, sending only stderr to the logger, you can use a construct like this, which I'm sure others will improve upon:

1 */8 * * * ( /path/to/myprog 2>&1 1>&3 | logger -p user.debug -t 'myprog' ) 3>&1

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .