redirecting stdout and stderr to /dev/null

Martin A. Brown martin at linux-ip.net
Sat May 7 15:16:00 EDT 2016


Hello there,

>I'm new to python but well versed on other languages such as C and 
>Perl
>
>I'm have problems redirecting stdout and stderr to /dev/null in a 
>program that does a fork and exec. T found this method googling 
>around and it is quite elegant compared to to the Perl version.
>
>So to isolate things I made a much shorter test program and it 
>still is not redirecting. What am I doing wrong?
>
>test program test.py
>----------------- cut here -------------------
>import sys
>import os
>
>f = open(os.devnull, 'w')
>sys.stdout = f
>sys.stderr = f
>os.execl("/bin/ping", "",  "-w", "20",  "192.168.1.1");
>------------------ cut here -------------------

Think about the file descriptors.

Unix doesn't care what the name is, rather that the process inherits 
the FDs from the parent.  So, your solution might need to be a bit 
more complicated to achieve what you desire.  Run the following to 
see what I mean.

  realstdout = sys.stdout
  realstderr = sys.stderr
  f = open(os.devnull, 'w')
  sys.stdout = f
  sys.stderr = f
  
  print("realstdout FD: %d" % (realstdout.fileno(),), file=realstdout)
  print("realstderr FD: %d" % (realstderr.fileno(),), file=realstdout)
  print("sys.stdout FD: %d" % (sys.stdout.fileno(),), file=realstdout)
  print("sys.stderr FD: %d" % (sys.stderr.fileno(),), file=realstdout)

That should produce output that looks like this:

  realstdout FD: 1
  realstderr FD: 2
  sys.stdout FD: 3
  sys.stderr FD: 3

I hope that's a good hint...

I like the idea of simply calling the next program using one of the 
exec() variants, but you'll have to adjust the file descriptors, 
rather than just the names used by Python.

If you don't need to exec(), but just run a child, then here's the 
next hint (this is for Python 3.5):

  import subprocess
  cmd = ["ping", "-w", "20",  "192.168.1.1"]
  devnull = subprocess.DEVNULL
  proc = subprocess.run(cmd, stdout=devnull, stderr=devnull)
  proc.check_returncode()

(By the way, your "ping" command looked like it had an empty token 
in the second arg position.  Looked weird to me, so I removed it 
in my examples.)

For subprocess.run, see:

  https://docs.python.org/3/library/subprocess.html#subprocess.run

For earlier Python versions without run(), you can use Popen():

  import subprocess
  cmd = ["/bin/ping", "-w", "20",  "192.168.1.1"]
  devnull = subprocess.DEVNULL
  proc = subprocess.Popen(cmd, stdout=devnull, stderr=devnull)
  retcode = proc.wait()
  if retcode != 0:
      raise FlamingHorribleDeath

You will have to define FlamingHorribleDeath or figure out what you 
want to do in the event of the various different types of 
failure....if you don't then, you'll just see this:

  NameError: name 'FlamingHorribleDeath' is not defined

Good luck,

-Martin

-- 
Martin A. Brown
http://linux-ip.net/



More information about the Python-list mailing list