title: dup, dup2, tmpfile and stdout in python
body: <p>This is a follow up question from <a href="https://stackoverflow.com/q/8804893/572616">here</a>.</p>
  <hr />
  <h3>Where I want do go</h3>
  <p>I would like to be able to temporarily redirect the stdout into a temp file, while python still is able to print to stdout. This would involve the following steps:</p>
  <ol>
  <li>Create a copy of stdout (<code>new</code>)</li>
  <li>Create a temp file (<code>tmp</code>)</li>
  <li>Redirect stdout into <code>tmp</code></li>
  <li>Tell python to use <code>new</code> as stdout</li>
  <li>Redirect <code>tmp</code> into the &quot;real&quot; stdout</li>
  <li>Tell python to use the &quot;real&quot; stdout again</li>
  <li>Read and close <code>tmp</code></li>
  </ol>
  <h3>Implementation</h3>
  <p>I tried to implement the above in the following way:</p>
  <pre><code>import os
  import subprocess
  import sys
  
  #A function that calls an external process to print to stdout as well as
  #a python print to pythons stdout.
  def Func(s, p = False):
      subprocess.call('echo &quot;{0}&quot;'.format(s), shell = True)
      if p:
          print &quot;print&quot;
  
  sil = list() # &lt;-- Some list to store the content of the temp files
  
  print &quot;0.1&quot; # Some testing of the
  Func(&quot;0.2&quot;) # functionality
  
  new = os.dup(1)    # Create a copy of stdout (new)
  tmp = os.tmpfile() # Create a temp file (tmp)
  
  os.dup2(tmp.fileno(), 1)            # Redirect stdout into tmp
  sys.stdout = os.fdopen(new, 'w', 0) # Tell python to use new as stdout
  
  Func(&quot;0.3&quot;, True) # &lt;--- This should print &quot;0.3&quot; to the temp file and &quot;print&quot; to stdout
  
  os.dup2(new, 1)                   # Redirect tmp into &quot;real&quot; stdout
  sys.stdout = os.fdopen(1, 'w', 0) # Tell python to use &quot;real&quot; stdout again
  
  # Read and close tmp
  tmp.flush()
  tmp.seek(0, os.SEEK_SET)
  sil.append(tmp.read())
  tmp.close()
  </code></pre>
  <p>I would like to take a little break here to summarize.<br />
  The output to console up until here should read:</p>
  <pre><code>0.1
  0.2
  print
  </code></pre>
  <p>while <code>sil</code> should look like this: <code>['0.3\n']</code>. So everything is working like a charm up until here. However, if I redo the script above again like so:</p>
  <pre><code>print &quot;1.1&quot; # Some testing of the
  Func(&quot;1.2&quot;) # functionality
  
  new = os.dup(1)    # Create a copy of stdout (new)
  tmp = os.tmpfile() # Create a temp file (tmp)
  
  os.dup2(tmp.fileno(), 1)            # Redirect stdout into tmp
  sys.stdout = os.fdopen(new, 'w', 0) # Tell python to use new as stdout
  
  # This should print &quot;0.3&quot; to the temp file and &quot;print&quot; to stdout and is the crucial point!
  Func(&quot;1.3&quot;, True) 
  
  os.dup2(new, 1)                   # Redirect tmp into &quot;real&quot; stdout
  sys.stdout = os.fdopen(1, 'w', 0) # Tell python to use &quot;real&quot; stdout again
  
  # Read and close tmp
  tmp.flush()
  tmp.seek(0, os.SEEK_SET)
  sil.append(tmp.read())
  </code></pre>
  <p>an error occurs and the output looks like this:</p>
  <pre><code>1.1
  1.2
  /bin/sh: line 0: echo: write error: Bad file descriptor
  print
  </code></pre>
  <p>while <code>sil</code> reads: <code>['0.3\n', '']</code>.</p>
  <p>In other words: the second <code>Func(&quot;1.3&quot;, True)</code> is not able to write to the temp file.</p>
  <h3>Questions</h3>
  <ol>
  <li>First of all, I would like to know why my script is not working like I want it to work. Meaning, why is it only possible in the first half of the script to write to the temp file?</li>
  <li>I am still a little puzzled by the usage of <code>dup</code> and <code>dup2</code>. While I think I understand how the redirection of stdout into a temp file is working I totally do now know why <code>os.dup2(new, 1)</code> is doing what it is doing. Maybe the answer could elaborate on what all the <code>dup</code> and <code>dup2</code>s in my script are doing^^</li>
  </ol>