Google Groups no longer supports new Usenet posts or subscriptions. Historical content remains viewable.
Dismiss

redirecting stdout and stderr to /dev/null

605 views
Skip to first unread message

Jim Dodgen

unread,
May 7, 2016, 2:46:51 PM5/7/16
to
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 -------------------


results when run

root@dev:/home/jim# python test.py
PING 192.168.1.1 (192.168.1.1) 56(84) bytes of data.
64 bytes from 192.168.1.1: icmp_seq=1 ttl=64 time=1.36 ms
64 bytes from 192.168.1.1: icmp_seq=2 ttl=64 time=1.00 ms
64 bytes from 192.168.1.1: icmp_seq=3 ttl=64 time=1.01 ms
64 bytes from 192.168.1.1: icmp_seq=4 ttl=64 time=1.16 ms
64 bytes from 192.168.1.1: icmp_seq=5 ttl=64 time=1.02 ms
^C
--- 192.168.1.1 ping statistics ---
5 packets transmitted, 5 received, 0% packet loss, time 4004ms
rtt min/avg/max/mdev = 1.002/1.114/1.361/0.136 ms
root@dev:/home/jim#

*Jim Dodgen*

Martin A. Brown

unread,
May 7, 2016, 3:22:59 PM5/7/16
to

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/

Jim Dodgen

unread,
May 7, 2016, 7:54:58 PM5/7/16
to
*Thanks for the help*



On Sat, May 7, 2016 at 12:16 PM, Martin A. Brown <mar...@linux-ip.net>
wrote:
The empty token is needed but useless, it is arg[0] most people just repeat
the program name


>
> 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/


seems not to find subprocess.DEVNULL

I'm on 2.7.6 Ubuntu, and 2.7.9 on Raspbian I expect I need 3.5

here are some Tracebacks I get, the second one is when I tried os.devnull
in place of subprocess.DEVNULL


Traceback (most recent call last):
File "test.py", line 5, in <module>
devnull = subprocess.DEVNULL
AttributeError: 'module' object has no attribute 'DEVNULL'


Traceback (most recent call last):
File "test.py", line 6, in <module>
proc = subprocess.Popen(cmd, stdout=os.devnull, stderr=os.devnull)
File "/usr/lib/python2.7/subprocess.py", line 702, in __init__
errread, errwrite), to_close = self._get_handles(stdin, stdout, stderr)
File "/usr/lib/python2.7/subprocess.py", line 1128, in _get_handles
c2pwrite = stdout.fileno()
AttributeError: 'str' object has no attribute 'fileno'


One other observation it looks as Popen behaves the same way as my fork
exec would

Chris Angelico

unread,
May 7, 2016, 8:10:27 PM5/7/16
to
On Sun, May 8, 2016 at 9:54 AM, Jim Dodgen <j...@dodgen.us> wrote:
> The empty token is needed but useless, it is arg[0] most people just repeat
> the program name

Far from useless. It's how a process learns its own name, and yes,
repeating the image name is the most common way to provide that.

> One other observation it looks as Popen behaves the same way as my fork
> exec would

Indeed. In fact, I would strongly recommend never using an explicit
fork/exec from Python - always use subprocess or equivalent. On
non-Unix platforms, fork/exec may not be available, but subprocess can
use other methods of invoking programs.

ChrisA

Jim Dodgen

unread,
May 7, 2016, 8:19:12 PM5/7/16
to
Thanks Chris

I now have things working using a version 3.4.3 it finds subprocess.DEVNULL
just fine

*Jim Dodgen*
> --
> https://mail.python.org/mailman/listinfo/python-list
>

Ben Finney

unread,
May 7, 2016, 9:21:42 PM5/7/16
to
Jim Dodgen <j...@dodgen.us> writes:

> I'm have problems redirecting stdout and stderr to /dev/null in a
> program that does a fork and exec.

You may be interested in the ‘python-daemon’ library
<URL:https://pypi.python.org/pypi/python-daemon/>. It takes care of all
the fiddly bits to turn your program into a well-behaved Unix daemon.

--
\ “I wish there was a knob on the TV to turn up the intelligence. |
`\ There's a knob called ‘brightness’ but it doesn't work.” |
_o__) —Eugene P. Gallagher |
Ben Finney

Ben Finney

unread,
May 7, 2016, 9:38:56 PM5/7/16
to
Chris Angelico <ros...@gmail.com> writes:

> On Sun, May 8, 2016 at 9:54 AM, Jim Dodgen <j...@dodgen.us> wrote:
> > The empty token is needed but useless, it is arg[0] most people just
> > repeat the program name
>
> Far from useless. It's how a process learns its own name, and yes,
> repeating the image name is the most common way to provide that.

In particular, a program's name may not be its file name; it can be
called by one of several different names dependeing on how it is
installed on the system.

Certainly the programmer writing the code cannot hard-code what the
command name will be that invokes the program. Only ‘sys.argv[0]’, read
at run time, can tell.

> Indeed. In fact, I would strongly recommend never using an explicit
> fork/exec from Python - always use subprocess or equivalent. On
> non-Unix platforms, fork/exec may not be available, but subprocess can
> use other methods of invoking programs.

I've already mentioned earlier, but to be sure: the ‘python-daemon’
library <URL:https://pypi.python.org/pypi/python-daemon/> takes care of
the details of becoming a Unix daemon process.

--
\ “… a Microsoft Certified System Engineer is to information |
`\ technology as a McDonalds Certified Food Specialist is to the |
_o__) culinary arts.” —Michael Bacarella |
Ben Finney

Jim Dodgen

unread,
May 7, 2016, 11:50:11 PM5/7/16
to
Great help. My Python program is a rewrite of a Perl program I wrote. An
interesting exercise.
The reason being it is targeted for a Raspberry Pi and for the Pi Python
has the most support.



*Jim Dodgen*







On Sat, May 7, 2016 at 6:38 PM, Ben Finney <ben+p...@benfinney.id.au>
wrote:
> --
> https://mail.python.org/mailman/listinfo/python-list
>
0 new messages