Damon
Damon

Reputation: 70206

Redirect to stdout in bash

Is there a filename that is assignable to a variable (i.e. not a magic builtin shell token like &1) that will let me redirect to stdout?

What I finally want to do is run something like this in a cron script:

LOG=/tmp/some_file
...
some_command 2>&1 >> $LOG
echo "blah" >> $LOG
...

Conveniently, this lets me turn off log noise by redirecting to /dev/null later when I'm sure there is nothing that can fail (or, at least, nothing that I care about!) without rewriting the whole script. Yes, turning off logging isn't precisely best practice -- but once this script works, there is not much that can conceivably go wrong, and trashing the disk with megabytes of log info that nobody wants to read isn't desired.
In case something unexpectedly fails 5 years later, it is still possible to turn on logging again by flipping a switch.

On the other hand, while writing and debugging the script, which involves calling it manually from the shell, it would be extremely nice if it could just dump the output to the console. That way I wouldn't need to tail the logfile manually.

In other words, what I'm looking for is something like /proc/self/fd/0 in bash-talk that I can assign to LOG. As it happens, /proc/self/fd/0 works just fine on my Linux box, but I wonder if there isn't such a thing built into bash already (which would generally be preferrable).

Upvotes: 8

Views: 23224

Answers (4)

Kessem Lee
Kessem Lee

Reputation: 1373

Use /dev/stdout

Here's another SO answer that mentions this solution: Difference between stdout and /dev/stdout

Upvotes: 9

Damon
Damon

Reputation: 70206

Thanks to the awesome hints by olibre and suvayu, I came up with this (for the record, version that I'm using now):

# log to file
# exec 1>> /tmp/logfile 2>&1

# be quiet
# exec 1> /dev/null 2>&1

# dump to console
exec 2>&1

Just need to uncomment one of the three, depending on what is desired, and don't worry about anything else, ever again. This either logs all subsequent output to a file or to console, or not at all.
No output duplicated, works universally the same for every command (without explicit redirects), no weird stuff, and as easy as it gets.

Upvotes: 5

oHo
oHo

Reputation: 54661

Basic solution:

#!/bin/bash
LOG=/dev/null

# uncomment next line for debugging (logging)
# LOG=/tmp/some_file

{
  some_command
  echo "blah"
} | tee 1>$LOG 2>&1

More evolved:

#!/bin/bash

ENABLE_LOG=0       # 1 to log standard & error outputs
LOG=/tmp/some_file

{
  some_command
  echo "blah"
} | if (( $ENABLE_LOG ))
then
  tee 1>$LOG 2>&1
fi

More elegant solution from DevSolar's idea:

#!/bin/bash

# uncomment next line for debugging (logging)
# exec 1> >(tee /tmp/some_file)  2>&1

some_command
echo "blah"

Upvotes: 7

suvayu
suvayu

Reputation: 4664

If I have understood your requirement clearly, the following should do what you want

exec 2>&1
exec >> $LOG

Stdout and stderr of all subsequent commands will be appended to the file $LOG.

Upvotes: 2

Related Questions