473,416 Members | 1,713 Online
Bytes | Software Development & Data Engineering Community
Post Job

Home Posts Topics Members FAQ

Join Bytes to post your question to a community of 473,416 software developers and data experts.

Using subprocess module to launch a shell shell script that itselfforks a process

I have a shell script script.sh that launches a Java process in the
background using the &-operator, like so:

#!/bin/bash
java ... arguments here ... &

In my Python code, I want to invoke this shell script using the
Subprocess module. Here is my code:

def resultFromRunning_(command):
"""Invokes a shell command, and returns the stdout response.

Args:
command: A string containing the complete shell command to
run.

Results:
A string containing the output of the command executed.

Raises:
ValueError if a non-zero return code is returned from the
shell.
OSError if command isn't found, inappropriate permissions,
etc.
"""

L = log4py.Logger().get_instance()
L.info("Executing: " + command)

p = subprocess.Popen(
command,
shell=True,
stdin=subprocess.PIPE,
stdout=subprocess.PIPE,
stderr=subprocess.STDOUT,
close_fds=True
)

outputChannel = p.stdout
output = outputChannel.read()

result = p.wait()
if result:
raise(ShellError(command, result, output))

L.info("Result = " + str(output))
return output

When running the aforementioned code, it kicks off the shell script,
and, the shell script kicks off the Java process. However, the Python
code never returns from outputChannel.read() until I explicitly kill
the Java process myself via the kill shell command.

I've researched this issue on Google and various other websites, and
maybe I'm missing the obvious, but I cannot seem to find any
documentation relevant to this problem. Lots of references to bugs
filed in the past, that appear to be fixed, or to websites talking
about how the Popen module has a 64K limit on its data queue size, but
nothing relevent to my situation.

Can anyone inform me or point me to the appropriate documentation on
how to properly invoke a shell command such that any spawned children
processes don't cause Python to hang on me? I assume it has something
to do with process groups, but I'm largely ignorant of how to control
those.

Thanks in advance.
Oct 8 '08 #1
7 6194
En Tue, 07 Oct 2008 21:43:41 -0300, Samuel A. Falvo II
<sa*******@gmail.comescribió:
I have a shell script script.sh that launches a Java process in the
background using the &-operator, like so:

#!/bin/bash
java ... arguments here ... &

In my Python code, I want to invoke this shell script using the
Subprocess module. Here is my code:

def resultFromRunning_(command):
"""Invokes a shell command, and returns the stdout response.

Args:
command: A string containing the complete shell command to
run.

Results:
A string containing the output of the command executed.

Raises:
ValueError if a non-zero return code is returned from the
shell.
OSError if command isn't found, inappropriate permissions,
etc.
"""

L = log4py.Logger().get_instance()
L.info("Executing: " + command)

p = subprocess.Popen(
command,
shell=True,
stdin=subprocess.PIPE,
stdout=subprocess.PIPE,
stderr=subprocess.STDOUT,
close_fds=True
)

outputChannel = p.stdout
output = outputChannel.read()

result = p.wait()
if result:
raise(ShellError(command, result, output))

L.info("Result = " + str(output))
return output

When running the aforementioned code, it kicks off the shell script,
and, the shell script kicks off the Java process. However, the Python
code never returns from outputChannel.read() until I explicitly kill
the Java process myself via the kill shell command.
Is your shell script doing something else, apart from invoking the java
process? If not, you could just invoke java directly from Python. Also,
you set stdin=PIPE - is your java process expecting some input? you're not
writing anything to stdin.
Anyway, it's better to use the communicate method instead (it uses select
to read from both stdout and stderr):

p = subprocess.Popen(...)
output = p.communicate()[0]
result = p.returncode
if result: ...

See
http://docs.python.org/library/subpr...en.communicate

--
Gabriel Genellina

Oct 8 '08 #2
On Oct 7, 6:23*pm, "Gabriel Genellina" <gagsl-...@yahoo.com.arwrote:
Is your shell script doing something else, apart from invoking the java *
process?
Obviously, yes. The script is some 150 lines long. But the hang-up
occurs because of the forked Java process, not the other lines.
If not, you could just invoke java directly from Python. Also, *
you set stdin=PIPE - is your java process expecting some input? you're not *
writing anything to stdin.
It does not expect input from stdin. However, this does not affect
any OTHER scripts or commands I run.

Let's remember to look at the objective facts: for shell scripts that
launch child processes of their own, Python hangs. For all other
types of commands, it works 100% as expected.
Anyway, it's better to use the communicate method instead (it uses select*
to read from both stdout and stderr):
That doesn't help me.
See *http://docs.python.org/library/subpr...ss.Popen.commu...
I have.
Oct 8 '08 #3
On Oct 8, 11:24*am, "Samuel A. Falvo II" <sam.fa...@gmail.comwrote:
It does not expect input from stdin. *However, this does not affect
any OTHER scripts or commands I run.
OK, so, I'm very confused as to why this would matter.

I removed the stdin=PIPE argument, and this works. Many thanks for
bringing this to my attention.

But, my question now is, WHY is this an issue? If the launched
process doesn't read from its stdin, why would it block? Hence my
question here:
Let's remember to look at the objective facts: for shell scripts that
launch child processes of their own, Python hangs. *For all other
types of commands, it works 100% as expected.
Meaning, if I launched the Java process directly, it works fine. If I
launch it from the shell script WITHOUT background execution, it works
fine. But when I launch it WITH background execution (e.g., with the
& suffix), then it blocks.

Any ideas, so I can write this into my log for future reference?

Thanks.

Oct 8 '08 #4
On Oct 8, 11:31*am, "Samuel A. Falvo II" <sam.fa...@gmail.comwrote:
I removed the stdin=PIPE argument, and this works. *Many thanks for
bringing this to my attention.
OK, I am confused. After observing a bug where the code works "every
other time", like clockwork, I've used strace to figure out what is
going on. In the times when "it works," it's only the shell script
complaining that it's already running.

So, I'm right back to square one. Even _without_ setting stdin=PIPE,
it fails to unblock. I'm left utterly bewildered.

The only thing I can think of is that the JVM's stdout is tied to the
shell script's stdout, because that's the only way it can remain open
upon the termination of the child process. I suppose, at this point,
the next place to look is in shell script syntax to find out how to
detach the JVM from the script's process group.
Oct 8 '08 #5
On Oct 8, 11:24*am, "Samuel A. Falvo II" <sam.fa...@gmail.comwrote:
On Oct 7, 6:23*pm, "Gabriel Genellina" <gagsl-...@yahoo.com.arwrote:
Is your shell script doing something else, apart from invoking the java*
process?

Obviously, yes. *The script is some 150 lines long. *But the hang-up
occurs because of the forked Java process, not the other lines.
If not, you could just invoke java directly from Python. Also, *
you set stdin=PIPE - is your java process expecting some input? you're not *
writing anything to stdin.

It does not expect input from stdin. *However, this does not affect
any OTHER scripts or commands I run.

Let's remember to look at the objective facts: for shell scripts that
launch child processes of their own, Python hangs. *For all other
types of commands, it works 100% as expected.
Anyway, it's better to use the communicate method instead (it uses select *
to read from both stdout and stderr):

That doesn't help me.
See *http://docs.python.org/library/subpr...ss.Popen.commu...

I have.
You should be nicer to Gabriel. He is a guru.
Oct 8 '08 #6
En Wed, 08 Oct 2008 15:24:39 -0300, Samuel A. Falvo II
<sa*******@gmail.comescribió:
On Oct 7, 6:23*pm, "Gabriel Genellina" <gagsl-...@yahoo.com.arwrote:
>you set stdin=PIPE - is your java process expecting some input? you're
not writing anything to stdin.

It does not expect input from stdin. However, this does not affect
any OTHER scripts or commands I run.
But it *does* affect how subprocess handles the child process internally.
Let's remember to look at the objective facts: for shell scripts that
launch child processes of their own, Python hangs. For all other
types of commands, it works 100% as expected.
Don't conclude too fast... I've tested a variant (using a Perl script as a
replacement instead of a Java program), and it worked fine:

<log>
gabriel@sleipnir:~$ cat foo.sh
#!/bin/sh
perl foo.pl&
echo End of foo.sh

gabriel@sleipnir:~$ cat foo.pl
#!/usr/bin/perl

for ($i=5; $i>0; $i--) {
print "$i seconds remaining...\n";
sleep(1);
}
print "End of foo.pl\n";

gabriel@sleipnir:~$ cat foo.py
#!/usr/bin/python2.5

import subprocess

command = "./foo.sh"

p = subprocess.Popen(command,
shell=True,
stdin=None,
stdout=subprocess.PIPE,
stderr=subprocess.STDOUT,
close_fds=True
)
print "py: before p.communicate"
output = p.communicate()[0]
print "py: after p.communicate"
print "py: returncode=",p.returncode
print "py: read",len(output),"bytes"
print "py: output=", repr(output)
print "py: End of foo.py"
gabriel@sleipnir:~$ ./foo.py
py: before p.communicate
py: after p.communicate
py: returncode= 0
py: read 143 bytes
py: output= 'End of foo.sh\n5 seconds remaining...\n4 seconds
remaining...\n3 seconds remaining...\n2 seconds remaining...\n1 seconds
remaining...\nEnd of foo.pl\n'
py: End of foo.py
gabriel@sleipnir:~$ uname -a
Linux debian 2.6.18-4-486 #1 Mon Mar 26 16:39:10 UTC 2007 i686 GNU/Linux
gabriel@sleipnir:~$
</log>

This was tested both with python 2.4.4 and 2.5.2
I don't think it's a Python problem, but something related to java and how
it handles stdin/stdout. Try with another program.
But, my question now is, WHY is this an issue? If the launched
process doesn't read from its stdin, why would it block?
Several reasons - the child process might send enough text to stderr to
fill its buffer, and if the parent process doesn't read from the other end
of the pipe, the child blocks. That's why I suggested to use communicate
instead of stdout.read() - it takes care of such cases.
The only thing I can think of is that the JVM's stdout is tied to the
shell script's stdout, because that's the only way it can remain open
upon the termination of the child process. I suppose, at this point,
the next place to look is in shell script syntax to find out how to
detach the JVM from the script's process group.
Can't you redirect to a file instead?
java foo.jar >/tmp/foo.log 2>&1 &

--
Gabriel Genellina

Oct 9 '08 #7
On Tue, Oct 07, 2008 at 05:43:41PM -0700, Samuel A. Falvo II wrote:
p = subprocess.Popen(
command,
shell=True,
stdin=subprocess.PIPE,
stdout=subprocess.PIPE,
stderr=subprocess.STDOUT,
close_fds=True
)

outputChannel = p.stdout
output = outputChannel.read()
You call read with no arguments. This is highly problematic in the
context of interprocess communication, unless you can be 100% positive
that none of the children will write anywhere besides STDOUT, and
won't try to read from STDIN in the meanwhile.

Python's read() with no args reads until the end of file, which in IPC
contexts is bad... Normally the child process won't close stdout
until it exits. So, if it did any other output in between, say, to
STDERR, the child will block waiting for the parent to read STDERR,
meanwhile the parent is blocked waiting for input from the child's
STDOUT, which results in a deadlock. Both processes sleep forever.
The exact same thing can happen if either the shell script or a
process started by the shell script tries to read from STDIN.

Since Java is launched by the shell script, it inherits the shell
script's STDIN, STDOUT, and STDERR file descriptors (i.e. the two
processes share the same STDIO). Thus if the java process writes to
STDERR, that also could be causing your deadlock.
On Wed, Oct 08, 2008 at 11:24:39AM -0700, Samuel A. Falvo II wrote:
On Oct 7, 6:23*pm, "Gabriel Genellina" <gagsl-...@yahoo.com.arwrote:
Is your shell script doing something else, apart from invoking the java*
process?
Obviously, yes.
It's far from obvious. I can't count the number of scripts I've seen
whose sole purpose was to launch a Java program (with the right
environment)... You would do well to avoid being dismissive and
listen to those who respond with help, when you are the one who
obviously doesn't understand the behavior you're getting, and you're
the one asking for help.
The script is some 150 lines long. But the hang-up
occurs because of the forked Java process, not the other lines.
I'm betting it's because the Java program is writing warnings to
STDERR (more data than will fit in the STDIO buffer), which you're not
reading...
If not, you could just invoke java directly from Python. Also, *
you set stdin=PIPE - is your java process expecting some input? you're not *
writing anything to stdin.
It does not expect input from stdin. However, this does not affect
any OTHER scripts or commands I run.
Irrelevant... Unless "any OTHER scripts" encompases all possible
combinations of process interactions, and you can demontstrate that it
does so, this proves nothing.
Let's remember to look at the objective facts: for shell scripts that
launch child processes of their own, Python hangs. For all other
types of commands, it works 100% as expected.
These are not facts which are in evidence. We don't know what your
script is doing, and it's clear that you yourself are not able to
explain the behavior you are seeing, therefore there is no reason for
us to conclude that the above statements are true and correct. Most
likely, they are not.
Anyway, it's better to use the communicate method instead (it uses select *
to read from both stdout and stderr):
That doesn't help me.
Please explain why it doesn't.

The most likely cause of the behavior you are seeing is the deadlock I
described, above. Using select() (i.e. using communicate()) should
generally fix about half the cases... The rest would be fixed by
redirecting STDIN of the child (or at least the Java process) from
/dev/null, most likely.

Then of course, there could be other explanations. But this being
overwhelmingly the most likely one, if you don't try those solutions,
there's no point in trying to help you further...

--
Derek D. Martin
http://www.pizzashack.org/
GPG Key ID: 0x81CFE75D
-----BEGIN PGP SIGNATURE-----
Version: GnuPG v1.2.1 (GNU/Linux)

iD8DBQFI7mPcdjdlQoHP510RAoxzAJ9IhLxvbW7TyViMHG5zLM gm4bKsbgCgncD1
72+6DU1/j0q7jb9HV+66wsw=
=M4yo
-----END PGP SIGNATURE-----

Oct 9 '08 #8

This thread has been closed and replies have been disabled. Please start a new discussion.

Similar topics

17
by: Michael McGarry | last post by:
Hi, I am just starting to use Python. Does Python have all the regular expression features of Perl? Is Python missing any features available in Perl? Thanks, Michael
3
by: Darren Dale | last post by:
I'm a developer on the matplotlib project, and I am having trouble with the subprocess module on windows (Python 2.4.2 on winXP). No trouble to report with linux. I need to use _subprocess instead...
5
by: Grant Edwards | last post by:
I'm trying to use the py-gnuplot module on windows, and have been unable to get it to work reliably under Win2K and WinXP. By default, it uses popen(gnuplotcmd,'w'), but in some situations that...
9
by: Phoe6 | last post by:
Hi all, Consider this scenario, where in I need to use subprocess to execute a command like 'ping 127.0.0.1' which will have a continuous non- terminating output in Linux. # code # This...
12
by: bhunter | last post by:
Hi, I've used subprocess with 2.4 several times to execute a process, wait for it to finish, and then look at its output. Now I want to spawn the process separately, later check to see if it's...
4
by: grayaii | last post by:
There are so many threads on this subject, but I ran across a situation on Windows that I can't figure out. I'm trying to run this little command-line exe and when I launch like this, it hangs:...
3
by: Thomas Jansson | last post by:
Dear all I have tkinkter based frontend to a Fortran based program. I use subprocess to launch the fortran program as a child process and I wish to see the output of the fortran program as it is...
9
by: erikcw | last post by:
Hi, I have a cgi script where users are uploading large files for processing. I want to launch a subprocess to process the file so the user doesn't have to wait for the page to load. What is...
2
by: Chuckk Hubbard | last post by:
If I run 'python -i subprocessclient.py' I expect to see the nice level of it go up 2, and the nice level of the subprocess go up 1. But all I see is the nice level of the client change. What am I...
0
by: emmanuelkatto | last post by:
Hi All, I am Emmanuel katto from Uganda. I want to ask what challenges you've faced while migrating a website to cloud. Please let me know. Thanks! Emmanuel
1
by: nemocccc | last post by:
hello, everyone, I want to develop a software for my android phone for daily needs, any suggestions?
0
by: Hystou | last post by:
There are some requirements for setting up RAID: 1. The motherboard and BIOS support RAID configuration. 2. The motherboard has 2 or more available SATA protocol SSD/HDD slots (including MSATA, M.2...
0
marktang
by: marktang | last post by:
ONU (Optical Network Unit) is one of the key components for providing high-speed Internet services. Its primary function is to act as an endpoint device located at the user's premises. However,...
0
by: Hystou | last post by:
Overview: Windows 11 and 10 have less user interface control over operating system update behaviour than previous versions of Windows. In Windows 11 and 10, there is no way to turn off the Windows...
0
tracyyun
by: tracyyun | last post by:
Dear forum friends, With the development of smart home technology, a variety of wireless communication protocols have appeared on the market, such as Zigbee, Z-Wave, Wi-Fi, Bluetooth, etc. Each...
0
agi2029
by: agi2029 | last post by:
Let's talk about the concept of autonomous AI software engineers and no-code agents. These AIs are designed to manage the entire lifecycle of a software development project—planning, coding, testing,...
0
isladogs
by: isladogs | last post by:
The next Access Europe User Group meeting will be on Wednesday 1 May 2024 starting at 18:00 UK time (6PM UTC+1) and finishing by 19:30 (7.30PM). In this session, we are pleased to welcome a new...
0
by: conductexam | last post by:
I have .net C# application in which I am extracting data from word file and save it in database particularly. To store word all data as it is I am converting the whole word file firstly in HTML and...

By using Bytes.com and it's services, you agree to our Privacy Policy and Terms of Use.

To disable or enable advertisements and analytics tracking please visit the manage ads & tracking page.