Daniel Jørgensen
Daniel Jørgensen

Reputation: 1202

Bash - send all output to a log file, BUT show errors

Is it possible within a bash script, to make all output, except the output i specifically output with echo, go to a log file, BUT if there's errors in the output it should show in the terminal (and the log file also ofcourse)?

Upvotes: 2

Views: 6299

Answers (2)

anubhava
anubhava

Reputation: 785108

Here is what you can do by using an additional file descriptor:

#!/bin/bash

# open fd=3 redirecting to 1 (stdout)
exec 3>&1

# redirect stdout/stderr to a file but show stderr on terminal
exec >file.log 2> >(tee >(cat >&3))

# function echo to show echo output on terminal
echo() {
   # call actual echo command and redirect output to fd=3
   command echo "$@" >&3
}

# script starts here
echo "show me"
printf "=====================\n"
printf "%s\n" "hide me"
ls foo-foo
date
tty
echo "end of run"

# close fd=3
exec 3>&-

After you run your script it will display following on terminal:

show me
ls: cannot access 'foo-foo': No such file or directory
end of run

If you do cat file.log then it shows:

=====================
hide me
ls: cannot access 'foo-foo': No such file or directory
Fri Dec  2 14:20:47 EST 2016
/dev/ttys002
  • On terminal we're only getting output of echo command and all the errors.
  • In the log file we're getting error and remaining output from script.

Upvotes: 4

slim
slim

Reputation: 41223

UNIX terminals usually provide two output file decriptors, stdout and stderr, both of which go to the terminal by default.

Well behaved programs send their "standard" output to stdout, and errors to stderr. So for example echo writes to stdout. grep writes matching lines to stdout, but if something goes wrong, for example a file can't be read, the error goes to stderr.

You can redirect these with > (for stdout) and 2> (for stderr). So:

 myscript >log 2>errors

Writes output to log and errors to errors.

So part of your requirement can be met simply with:

 command >log

... errors will continue to go to the terminal, via stdout.

Your extra requirement is "except the output i specifically output with echo".

It might be enough for you that your echos go to stderr:

 echo "Processing next part" >&2

The >&2 redirects stdout from this command to stderr. This is the standard way of outputting errors (and sometimes informational output) in shell scripts.

If you need more than this, you might want to do something more complicated with more file descriptors. Try: https://unix.stackexchange.com/questions/18899/when-would-you-use-an-additional-file-descriptor

Well behaved UNIX programs tend to avoid doing complicated things with extra file descriptors. The convention is to restrict yourself to stdout and stderr, with any further outputs being specified as filenames in the command line parameters.

Upvotes: 3

Related Questions