There is a script run via cron with the following line:
0 * * * * (/var/script.sh | tee -a /var/script.log)
How do I rewrite the cron entry to capture both normal
stdout and error
stderr output? They are to be placed in different files.
Unix & Linux Stack Exchange is a question and answer site for users of Linux, FreeBSD and other Un*x-like operating systems. It only takes a minute to sign up.Sign up to join this community
cron jobs are run by
sh by default, and regardless of whether
sh is a Bourne or POSIX
sh or compatible, the syntax would be:
0 * * * * /var/script.sh 2>&1 | tee -a /var/script.log
| causes the two commands on either side to be run in parallel connected with a pipe with the stdout (fd 1) of the left one plugged to the writing end of the pipe and the stdin (fd 0) of the right one plugged to the reading end.
2>&1 to the left one, we have the fd 2 (stderr) point to the same resource as pointed out by fd 1: the writing end of the pipe, so both the normal and error output of
script.sh will go to the pipe to
tee will write it both to its stdout (which in the case of a cron job is either a pipe or temp file that will be used to send an email to the user) and to
That syntax also works in the
bash (4.0 or newer), you can also do:
SHELL=/bin/zsh # or tcsh, bash ... 0 * * * * /var/script.sh |& tee -a /var/script.log
SHELL=/bin/zsh is how you tell
cron to use a different shell to interpret the command lines).
fish, you'd use
&| instead of
rc (the once to be successor of
sh) or derivatives, the syntax is:
SHELL=/bin/rc # or es, akanga 0 * * * * /var/script.sh >[2=1] | tee -a /var/script.log
zsh, you can also do without
tee thanks to its
SHELL=/bin/zsh 0 * * * * /var/script.sh >&1 2>&2 >>& /var/script.log
Which would also have the benefit of preserving
script.sh's exit status, and also keeps
script.sh's stderr going to the original stderr in addition to
script.log (though that doesn't make much of a difference in a cron job where stdout and stderr generally go to the same place anyway).
A few Bourne/POSIX like shells (
mksh at least) have a
pipefail option which you can use to be able to report errors in any component of a pipeline:
SHELL=/bin/ksh # or zsh, bash... 0 * * * * set -o pipefail && /var/script.sh 2>&1 | tee -a /var/script.log
cron wants to tell you about any cron job that produces output. It wants to email the results to you. If you don't want to receive email from cron, ensure your jobs produce no output: don't use
tee, just redirect the output
0 * * * * /var/script.sh >> /var/script.log 2>&1
Note also I removed the parentheses: there's no point in running the script in a subshell.