title: Save stdout, stderr and stdout+stderr synchronously
body: <p>For testing purposes, I would like to save stdout and stderr <em>separately</em> for inspection by subsequent code. For example, a test run with erroneous input should result in output to stderr, but nothing on stdout, while a test run with correct input should result in output to stdout, but nothing to stderr. The saving has to be synchronous, to avoid race conditions with the tests (so I can't use <a href="https://stackoverflow.com/questions/4489139/bash-process-substitution-and-syncing">process substitution</a>).</p>
  
  <p>To be able to debug the test after the fact, I <strong>also</strong> need to see stdout and stderr in the sequence they were output. So I have to either save them both to the same file/variable/whatever or send them to the terminal at the same time as saving them separately.</p>
  
  <p>To test which error happened, I <strong>also</strong> need the exit code of the command.</p>
  
  <p>For reasons of efficiency and accuracy, I of course cannot run each test twice.</p>
  
  <p>Is it for example possible to redirect stdout to stdout.log, stderr to stderr.log, <em>and</em> both of them to output.log in the same command? Or to use a <strong>synchronous</strong> <code>tee</code> command separately for stdout and stderr? Or to save a copy of stdout and stderr to separate variables?</p>
  
  <p><strong>Update</strong>: It looks like tim's solution almost works (modified to output on terminal instead of logging to all.log):</p>
  
  <pre><code>$ set -o pipefail
  $ {
      {
          echo foo | tee stdout.log 2&gt;&amp;3 3&gt;&amp;-
      } 2&gt;&amp;1 &gt;&amp;4 4&gt;&amp;- | tee stderr.log 2&gt;&amp;3 3&gt;&amp;-
  } 3&gt;&amp;2 4&gt;&amp;1
  foo
  $ cat stdout.log
  foo
  $ cat stderr.log
  $ {
      {
          echo foo &gt;&amp;2 | tee stdout.log 2&gt;&amp;3 3&gt;&amp;-
      } 2&gt;&amp;1 &gt;&amp;4 4&gt;&amp;- | tee stderr.log 2&gt;&amp;3 3&gt;&amp;-
  } 3&gt;&amp;2 4&gt;&amp;1
  foo
  $ cat stdout.log
  $ cat stderr.log
  foo
  $ bar=$({
      {
          echo foo | tee stdout.log 2&gt;&amp;3 3&gt;&amp;-
      } 2&gt;&amp;1 &gt;&amp;4 4&gt;&amp;- | tee stderr.log 2&gt;&amp;3 3&gt;&amp;-
  } 3&gt;&amp;2 4&gt;&amp;1)
  $ echo "$bar"
  foo
  $ cat stdout.log
  foo
  $ cat stderr.log
  $ bar=$({
      {
          echo foo &gt;&amp;2 | tee stdout.log 2&gt;&amp;3 3&gt;&amp;-
      } 2&gt;&amp;1 &gt;&amp;4 4&gt;&amp;- | tee stderr.log 2&gt;&amp;3 3&gt;&amp;-
  } 3&gt;&amp;2 4&gt;&amp;1)
  $ cat stdout.log
  $ cat stderr.log
  foo
  $ echo "$bar"
  foo
  </code></pre>
  
  <p>This seems to work except for the last iteration, where the value of <code>bar</code> is set to the contents of stderr. Any suggestions for all of these to work?</p>