CyGuy
CyGuy

Reputation: 79

redirect stdout and stderr to one file, copy of just stderr to another

I want to redirect the output of stdout and stderr to a common file:

./foo.sh >stdout_and_stderr.txt 2>&1

But also redirect just stderr to a separate file. I tried variations of:

./foo.sh >stdout_and_stderr.txt 2>stderr.txt 2>&1

but none of them work quite right in bash, e.g. stderr only gets redirected to one of the output files. It's important that the combined file preserves the line ordering of the first code snippet, so no dumping to separate files and later combining.

Is there a neat solution to this in bash?

Upvotes: 4

Views: 1266

Answers (3)

Jonathan Leffler
Jonathan Leffler

Reputation: 755054

Using process substitution, you can get a moderate approximation to what you're after:

file1=stdout.stderr
file2=stderr.only
: > $file1    # Zap the file before starting
./foo.sh >> $file1 2> >(tee $file2 >> $file1)

This names the files since one of the names is repeated. The standard output is written to $file1. Standard error is written to the pipeline, which runs tee and writes one copy of the input (which was standard error output) to $file2, and also writes a second copy to $file1 as well. The >> redirections mean that the file is opened with O_APPEND so that each write will be done at the end, regardless of what the other process has also written.

As noted in comments, the output will, in general, be interleaved differently in this than it would if you simply ran ./foo.sh at the terminal. There are multiple sets of buffering going on to ensure that is what happens. You might also get partial lines because of the ways lines break over buffer size boundaries.

Upvotes: 1

Dennis Williamson
Dennis Williamson

Reputation: 360683

You can use an additional file descriptor and tee:

{ foo.sh 2>&1 1>&3- | tee stderr.txt; } > stdout_and_stderr.txt 3>&1

Be aware that line buffering may cause the stdout output to appear out of order. If this is a problem, there are ways to overcome that including the use of unbuffer.

Upvotes: 3

BaZZiliO
BaZZiliO

Reputation: 232

This comment from @jonathan-leffler should be an answer:

Note that your first command (./foo.sh 2>&1 >file) sends errors to the original standard output, and the standard output (but not the redirected standard error) to the file.

If you wanted both in file, you'd have to use ./foo.sh >file 2>&1, reversing the order of the redirections.

They're interpreted reading left to right.

Upvotes: 0

Related Questions