From: Sudheer on
Hi,
What's wrong with the following code. The program waits indefenitely
at 'output = p2.stdout.read()'


from subprocess import *

p1=Popen(['tr', 'a-z', 'A-Z'],stdin=PIPE,stdout=PIPE)
p2=Popen(['tr','A-Z', 'a-z'],stdin=p1.stdout,stdout=PIPE)
p1.stdin.write("hello")
p1.stdin.close()

output = p2.stdout.read()

print output


--
Thanks
Sudheer
From: Chris Rebert on
On Sat, Jul 3, 2010 at 7:33 AM, Sudheer <inbox1.sudheer(a)gmail.com> wrote:
> Hi,
>  What's wrong with the following code. The program waits indefenitely
> at  'output = p2.stdout.read()'
>
>
> from subprocess import *
>
> p1=Popen(['tr', 'a-z', 'A-Z'],stdin=PIPE,stdout=PIPE)
> p2=Popen(['tr','A-Z', 'a-z'],stdin=p1.stdout,stdout=PIPE)
> p1.stdin.write("hello")
> p1.stdin.close()
>
> output = p2.stdout.read()
>
> print output

Try using .communicate() instead of reading and writing to .stdin and .stdout.
Adding a newline (i.e. "hello\n") may also help.

Cheers,
Chris
--
http://blog.rebertia.com
From: Nobody on
On Sat, 03 Jul 2010 10:33:49 -0400, Sudheer wrote:

> What's wrong with the following code. The program waits indefenitely
> at 'output = p2.stdout.read()'
>
>
> from subprocess import *
>
> p1=Popen(['tr', 'a-z', 'A-Z'],stdin=PIPE,stdout=PIPE)
> p2=Popen(['tr','A-Z', 'a-z'],stdin=p1.stdout,stdout=PIPE)
> p1.stdin.write("hello")
> p1.stdin.close()
>
> output = p2.stdout.read()
>
> print output

The problem is that p2 is inheriting Python's copy of the write end of the
pipe corresponding to p1.stdin, which means that it's impossible to
generate EOF on the pipe (i.e. p1.stdin.close() is a no-op):

PID TTY STAT TIME COMMAND
30437 pts/1 S+ 0:00 /usr/bin/python2.6 ./test.py
30438 pts/1 S+ 0:00 tr a-z A-Z
30439 pts/1 S+ 0:00 tr A-Z a-z

/proc/30437/fd:
total 0
lrwx------ 1 user users 64 Jul 3 20:51 0 -> /dev/pts/1
lrwx------ 1 user users 64 Jul 3 20:51 1 -> /dev/pts/1
lrwx------ 1 user users 64 Jul 3 20:51 2 -> /dev/pts/1
lr-x------ 1 user users 64 Jul 3 20:51 3 -> pipe:[31472684]

/proc/30438/fd:
total 0
lr-x------ 1 user users 64 Jul 3 20:51 0 -> pipe:[31472681] <= ***
l-wx------ 1 user users 64 Jul 3 20:51 1 -> pipe:[31472682]
lrwx------ 1 user users 64 Jul 3 20:51 2 -> /dev/pts/1

/proc/30439/fd:
total 0
lr-x------ 1 user users 64 Jul 3 20:51 0 -> pipe:[31472682]
l-wx------ 1 user users 64 Jul 3 20:51 1 -> pipe:[31472684]
lrwx------ 1 user users 64 Jul 3 20:51 2 -> /dev/pts/1
l-wx------ 1 user users 64 Jul 3 20:51 4 -> pipe:[31472681] <= ***

On Unix, you can add close_fds=True when creating p2, but that won't work
on Windows (it prevents redirection of stdin/stdout/stderr). OTOH, I don't
know whether the problem exists on Windows; if it doesn't just set
close_fds to True on Unix and False on Windows.

Alternatively, on Unix you should be able to use:

fcntl(fd, F_SETFD, FD_CLOEXEC)

(from the fcntl module) to prevent the write end of the pipe from being
inherited.

Worse still, killing the script with Ctrl-C will leave both of the child
processes behind.

In C, you would typically close the unused ends of the pipes within the
child half of the fork(), before the exec(), but you don't have that
degree of control with subprocess.

On Windows, you can chose whether a handle is inheritable or not, but I
don't know whether you can do that from within Python.