2

I have a script (fragment) for which I'm logging output and standard error:

#!/bin/sh
#...
{
   date "+%Y-%m-%d %T"
   cd $workdir
   ls -ltr validfile badfile #example command that provides stdout, stderr
} | tee -a $logfile

If I do the above, I get standard out in the logfile. To get standard error there also, I could do this:

#!/bin/sh
#...
{
   date "+%Y-%m-%d %T"
   cd $workdir
   ls -ltr validfile badfile
} 2>&1 | tee -a $logfile

But this version in a script when called from the command line won't allow me to parse out errors:

$ ./script.sh 2>/dev/null

Will simply show all standard out and standard error. What if, this time, I do want to just devnull the errors?

Can you show me how to pipe standard error to the log, but leave it on standard error for when it's called via command line or another script?

AIX 7.1, ksh (no bash)

3

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.

| improve this answer | |

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.