6

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).

Damon
  • 67,688
  • 20
  • 135
  • 185
  • You seem to be looking for [this](http://stackoverflow.com/questions/3173131/redirect-copy-of-stdout-to-log-file-from-within-bash-script-itself). – devnull Jul 31 '13 at 11:25
  • Great use case, but the wording of the question's title does not do it justice - perhaps something along the lines of 'persistent redirection of stdout and stderr in bash'. Also, given the solutions found, I suggest updating the question to make it focus on the _intent_ rather than your original solution attempt. – mklement0 Jul 31 '13 at 14:23

4 Answers4

7

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"
Community
  • 1
  • 1
oHo
  • 51,447
  • 27
  • 165
  • 200
  • In particular, I like solutions 2 and 3 (though at least 3 that I've tried does not do what I wanted). The hint about `exec` is gold, in any case. That was exactly the thing I needed, thank you. – Damon Jul 31 '13 at 12:46
3

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.

Damon
  • 67,688
  • 20
  • 135
  • 185
  • Yep perfect ;-) In my answer I did not managed the `crontab` case where output needs to be discarded +1 (I have forgotten that case while writing the answer!) – oHo Jul 31 '13 at 13:00
  • 1
    Great summary; one thing worth adding (based on @devnull's [link](http://stackoverflow.com/questions/3173131/redirect-copy-of-stdout-to-log-file-from-within-bash-script-itself)): To capture stderr and stdout in a file AND output to stdout at the same time, use `exec &> >(tee /tmp/logfile)` – mklement0 Jul 31 '13 at 14:01
3

Use /dev/stdout

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

Gabi Lee
  • 1,193
  • 8
  • 13
2

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.

suvayu
  • 4,271
  • 2
  • 29
  • 35
  • Misunderstood my intent, but nevertheless very good, thank you. This gave me the info I needed (didn't know that you could do use `exec` in this way). – Damon Jul 31 '13 at 12:45