Python: Why does subprocess() start 2 processes in

2019-05-07 18:22发布

问题:

I've written small gui-frontend in Python that lets users play internet radio channels. The program uses Pythons subprocess() to initizalize mplayer in order to tune into a channel, e.g.:

runn = "mplayer http://77.111.88.131:8010"
p = subprocess.Popen(runn, shell=True)
pid = int(p.pid)
wait = os.waitpid(p.pid, 1)

Then saves p.pid, and when a user wants to stop listening the following code is used:

os.kill(p.pid, 9)

This works perfectly in OpenSUSE, but not in Ubuntu. It seems that Ubuntu actually starts two separate processes. Terminal output:

Opensuse 11.3:

$ pgrep mplayer
22845

Ubuntu 10.04:

$ pgrep mplayer
22846
22847

This also applies when running other programs. Does anyone know why? I really want this app to run on all distros, so any help is deeply appreciated.

回答1:

Try this:

p = subprocess.Popen(runn.split(), shell=False)

My guess as to what's going on is this...

When you say shell=True subprocess actually starts this command sh -c "your string". The sh command then interprets your string and runs the command as if you'd typed that in at the shell prompt (more or less). Normally this would result in two processes. One would be sh -c "your string" and the other would be it's child, your string.

Some versions of sh have an optimization in which they will automatically exec the command under certain conditions. They do it if it's the last command sh is going to run and sh has no other reason to stick around. When using sh -c to run a command, this will almost always result in that invocation of sh replacing itself with the command it's running, thereby resulting in one process.

In my opinion it's a really, really bad idea to ever invoke subprocess.Popen with shell=True. You are opening yourself up for a ton of security issues by doing that, and generally less predictable behavior because shell metacharacters are interpreted by sh -c.



回答2:

I don't have an exact answer, but here are several ways to investigate:

Use pstree to examine the parent/child relationship between the processes.

Use ps -awux to view the full the command line arguments for all of the processes.

Note that using shell=True starts a shell process (e.g., /bin/bash) which starts mplayer. That might be another avenue for investigation. Are both systems using the same shell?

Are both systems using the same version of mplayer? of python?



回答3:

subprocess.Popen returns a Popen object with several useful methods. It's probably a bad idea to terminate things by directly using os.kill...

Does the same thing happen if you use the Popen object's p.terminate() or p.kill() methods?