Using some fancy output redirection, it is possible to achieve this without your basic bash redirection-to-processes.
Logging standard error and keeping it on the standard error pipe
#!/bin/sh exec 4>&1 # important as it "saves" stdout (usually /dev/tty2 for example) exec 3>&1 # work-in-progress file descriptor logfile=/var/log/myscript.out { { date "+%Y-%m-%d %T" cd $workdir ls -ltr validfile badfile } 2>&1 1>&3 | tee -a $logfile 1>&2 2>/dev/null 3>&4 } 3>&1 | tee -a $logfile exec 4>&- # proper form is to clean up when you're done exec 3>&-
Explanation:
exec 4>&1
and exec 3>&1
make new file descriptors 3 and 4, which both point to whatever standard out is pointing to (your terminal, most likely).
2>&1
redirects standard error of the whole second-level curly brace to standard out. 1>&3
redirects standard out to whatever fd3 is pointing to (which is standard out, but just not in pipe 1, which is significant!)
| tee -a $logfile
duplicates standard in (coming from the second-level curly braces, so the old stderr) to both the logfile and also standard out. 1>&2
moves standard out to standard error (so back where it belongs). 2>/dev/null
probably isn't necessary, but it redirects any error output from tee and trashes it. 3>&4
redirects pipe 3 to pipe 4 (which incidentally is pointing to stdout, remember?).
3>&1
takes pipe 3 of the first-level braces and sends it to regular standard out. | tee -a $logfile
captures standard input (which is the [adjusted] standard out of the braces) and duplicates it to the log and to standard out.