zwol
zwol

Reputation: 140718

Dynamically choose between redirecting to file and piping to a process

Suppose a shell script with the general form

(
    # ... lots of code here
) > logfile 2>&1

There is a feature request to optionally have the logs dumped to the terminal as well as the file, which would be written

(
    # ... lots of code here
) 2>&1 | tee logfile

The question is, how do I switch between these two pipeline constructs based on the value of a shell variable? Ideally without requiring a cat process, or anything like that, in the case where the logs are not going to the terminal, for efficiency.

It is a hard requirement to use POSIX shell features only. Also, due to bugs in older versions of zsh, the code inside the parentheses cannot be moved into a shell function.

Upvotes: 1

Views: 45

Answers (2)

root
root

Reputation: 6058

Using cat shouldn't be a problem, but if it is:

switcher.sh:

#!/bin/sh

if $TERMINAL; then
    OUTFILE=/dev/tty
else
    OUTFILE=/dev/null
fi

(
    echo hello
) | tee logfile > $OUTFILE

echo "## log file ##"
cat logfile
$ TERMINAL=false ./switcher.sh 
## log file ##
hello
$ TERMINAL=true ./switcher.sh 
hello
## log file ##
hello

The implementation of tee and /dev/null is such that there won't be extra buffer copies.

Upvotes: 0

Jens
Jens

Reputation: 72687

My take would be

(
   # ... lots of code here
) 2>&1 |
if test "$want_terminal_output" = yes; then
   tee logfile
else
   cat > logfile
fi

Yes, there's a (useful!) cat. Is efficiency of a single program really critical? I can see why anyone would consider it unaesthetic. If it hurts your eyes, write a read/write loop in the shell and profile it. Of course you can always duplicate lots of code and avoid the cat with the cut-n-paste way of programming so popular in this day and age :-)

Upvotes: 2

Related Questions