1

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.

1
  • @glennjackman Could you extend your comment to an answer, please. So it could also cover redirecting stderr output to the file. Nov 1, 2021 at 5:31

2 Answers 2

2

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

Where the | 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.

By adding 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.

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 script.log.

That syntax also works in the fish shell.

With (t)csh, zsh or bash (4.0 or newer), you can also do:

SHELL=/bin/zsh # or tcsh, bash ...
0 * * * * /var/script.sh |& tee -a /var/script.log

(where SHELL=/bin/zsh is how you tell cron to use a different shell to interpret the command lines).

In fish, you'd use &| instead of |&.

With 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

With zsh, you can also do without tee thanks to its MULT_IOS feature:

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 (bash, ksh93, zsh, yash, 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
1
  • So many thanks for that much detail! Oct 31, 2021 at 9:58
1

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.

1
  • D'oh!, Thank you @Stéphane as always! Nov 1, 2021 at 16:30

You must log in to answer this question.

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