So I want to log the output (stdout & stderr) of my non-interactive zsh shell scripts to both stdout and a log file, and to configure that capability from within the script itself.
With bash scripts, I've used the following and it works perfectly:
#!/bin/bash
exec &> >(tee -a /path/to/logfile)
Everything that follows prints both to stdout and to a log file.
But when I change the script to run with #!/bin/zsh
, the script will hang when it gets to the exec
line.
For example, if the script were this:
#!/bin/zsh
echo 'test'
exec &> >(tee -a /path/to/logfile)
Then when running it, stdout will hang showing this:
test_script.sh:2> echo test
Annoyingly, in the hanged state, Ctrl-C won't kill the process. Only way I know to get control of my terminal back is to background the process with Ctrl-Z and then kill the pid. (Took me a while to figure that out.)
Anyway, I'd like to know how I can achieve the same result in zsh. Ideally I'd also really like to understand why zsh is behaving differently from bash.
Thank you!
CodePudding user response:
You can't do it that way in zsh
, as after exec >(cmd)
, zsh
will be wanting to wait for the process substitution to finish before carrying on.
You could however do:
#! /bin/zsh -
{
# the whole script goes here
} >&1 >> file.log 2>&1
(no need for tee
, as zsh
can redirect to multiple files using its all internal tee
ing when you redirect some fd several times).
CodePudding user response:
I (finally) discovered a way to do this in a way compatible with both bash and zsh:
#!/bin/bash or #!/bin/zsh
exec > >(tee -a path/to/logfile) 2>&1
As a bonus, I also discovered how to change redirection of logging to different files within the same script.
#!/bin/bash or #!/bin/zsh
exec 3>&1
exec > >(tee -a path/to/logfile-1) 2>&1
echo "Copies stdout and stderr to first logfile"
exec >&3
exec > >(tee -a path/to/logfile-2) 2>&1
echo "Copies stdout and stderr to second logfile (and not the first)"
I admit I don't fully understand why this works, and why exec behaves differently with what I tried before, but I'm using this method now with no issues.
Thank you to all who've responded!