Is it possible to print only stdout to the screen while writing stdout and stderr to a logfile?

Viewed 1268

I know that it is possible to redirect both to a specific file:

./command 1> out.log 2> err.log

or

./command 1>test.log 2>&1

to write both to a file. But I don't know a way to write both to the same file (preserving the output order) while printing just one of both. tee isn't very helpful because it prints both file descriptors.

5 Answers

Writing standard output to one file and both to another is fairly simple with tee:

{ cmd | tee stdout.log; } &> both.log

Both descriptors of the compound command are redirected to both.log, but the standard output of cmd is first passed through tee to stdout.log before also being written to both.log.

Writing standard error to one and both to another is trickier.

{ foo 2>&1 1>&3 | tee stderr.log ; } 3>&1 | tee both.log > /dev/null

It's a little tricky to describe correctly. First, the command group's standard error is ignored; it's standard output is the pipe to tee both.log. But 3>&1 also copies its fd 3 to its standard output. So the question is, what gets written to that?

Inside the command group, foo's standard output is the pipe to tee stderr.log. The 2>&1 copies tee's standard error to that descriptor, and 1>&3 copies foo's standard output to the inherited fd 3.

It will be better to write them to different files, in this case it will be very easy:

cmd 2>/stderr.log| tee -a stdout.log

But if you want a single file, you will need some tricks here and additional process running for redirection.

You can use several redirections:

foo () { echo 1 ; echo 2 >&2 ; }
(( foo | tee >(cat) >&3) &>log ) 3>&1

The tee command sends the stdout to file descriptors 1 (through the process substitution) and 3. Both stdout and stderr are redirected to the log. In the end, 3, the copy of stdout, is sent back to the terminal.

Alternatively, you can do without the process substitution, redirect the output directly to log, but use -a and >> for append. You need to clear the log beforehand.

: > log; (( foo | tee -a log >&3) 2>> log ) 3>&1

stdout to the console and stdout and error to a file?

{ cmd | tee /dev/tty; } &> /tmp/both.log

To answer the question :

stderr to the console and stdout and error to a file?

{ cmd 3>&1 1>&2 2>&3 | tee /dev/tty; } &> /tmp/both.log

3>&1 1>&2 2>&3 means swapping stdout and stderr

Related