As far as I know, there is no elegant way of doing this (for an inelegant way that works but ain't pretty, scroll down to the end of my answer). I doubt you can do any better than:
$ command >stdout.txt 2>stderr.txt && cat stdout.txt stderr.txt > both.txt
There are various cool tricks you can use but none of them seems to succeed in producing the 3 files any better than the above. The main problem is that the file both.txt
will not show the messages (STDERR and STDOUT) in the correct order. This is because (as explained here):
When you redirect both standard output and standard error to the same
file, you may get some unexpected results. This is due to the fact
that STDOUT is a buffered stream while STDERR is always unbuffered.
This means that every character of STDERR is written as soon as it is
available while STDOUT writes stuff in batches. When both STDOUT and
STDERR are going to the same file you may see error messages appear
sooner than you would have expected them in relation to the actual
output of your program or script. It isn’t anything to be alarmed
about but is simply a side-effect of buffered vs. unbuffered streams,
you just need to keep it in mind.
The best alternative I could find was using bash subshells, is kind of complex and still does not display the output in the correct order. I made a simple Perl script, test.pl
that prints "OUT" to STDOUT
and "ERR" to STDERR
, repeating the process 3 times:
#/usr/bin/perl
for($i=0; $i<=2; $i++){
print STDOUT "OUT\n";
print STDERR "ERR\n"
}
Its normal, un-redirected output is :
$ ./test.pl
OUT
ERR
OUT
ERR
OUT
ERR
To redirect output(s) I ran:
(./test.pl 2> >(tee error.txt) > >(tee out.txt)) > both.txt
This uses tee
, a program that will print its input to screen and to a file name. So, I am redirecting STDERR
and passing it as input to tee
, telling it to write it to the file error.txt
. Similarly with STDOUT
and the file out.txt
. I am placing the whole thing in a subshell ((...)
) so I can then capture all of its output and redirect to both.txt
.
Now, this works inasmuch as it creates 3 files, one with STDERR
, one with STDOUT
and one with both. However, as explained above, this results in the messages appearing in the incorrect order in both.txt
:
$ cat both.txt
ERR
ERR
ERR
OUT
OUT
OUT
The only way around this I could find was to append the time it was printed to each line of output and then sorting, but it is getting seriously convoluted and, in your place, I would ask myself if it is really worth it:
$(./test.pl \
2> >(while read n; do echo `date +%N`" $n"; echo "$n" >>error.txt; done) \
> >(while read n; do echo `date +%N`" $n"; echo "$n" >> out.txt; done )) \
| gawk '{print $2}'> both.txt
There are various versions of tee
that can be downloaded (or created using VBS or JScript), and you could redirect stderr to stdout and pipe everything through tee. But then you would get both stdout and stderr to both the console and the file.
I believe it is impossible to send both to a file, yet selectively send stderr to the console, unless there is something special in the content of all errors that could be used to identify an error. I doubt there is a consistent unique identifier for errors, but if there is, the solution could look something like this:
yourScript 2>&1 | tee output.log | find "Error:"
Best Answer
You can define a function (e.g., in your
.alias
,.bashrc
file)This can then be used as
For example