Reputation: 79
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
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
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
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