Rufus
Rufus

Reputation: 5566

Check if subprocess called with shell=True is still running

I have a process which for certain reasons, I must call with the following (please don't judge...)

process = subprocess.Popen("some_command &", shell=True, executable='/bin/bash')

some_command is supposed to terminate by itself when some external conditions are met.

How can I check when some_command has terminated?

process.poll() 

always returns 0

A simple script to demonstrate my situation:

import subprocess

process = subprocess.Popen("sleep 5 &", shell=True, executable='/bin/bash')

while True:
    print(process.poll())

Upvotes: 0

Views: 256

Answers (1)

ShadowRanger
ShadowRanger

Reputation: 155604

some_command & tells bash to run some_command in the background. This means that your shell launches some_command, then promptly exits, severing the tie between the running some_command and your Python process (some_command's parent process no longer exists after all). poll() is accurately reporting that bash itself finished running, exiting with status 0; it has no idea what may or may not be happening with some_command; that's bash's problem (and bash didn't care either).

If you want to be able to poll to check if some_command is still running, don't background it via bash shell metacharacters; without &, bash will continue running until it finishes, so you'll have an indirect indication of when some_command finishes from the fact that bash itself is still running. It's still in the background (in the sense that it runs in parallel with your Python code; the Python process won't stall waiting on it or anything unless you explicitly wait or communicate with process):

process = subprocess.Popen("some_command", shell=True, executable='/bin/bash')

Of course, unless some_command is some bash builtin, bash is just getting in the way here; as noted subprocess.Popen always runs stuff in the background unless you explicitly ask for it to wait, so you didn't need bash's help to background anything:

process = subprocess.Popen(["some_command"])

would get similar behavior, and actually let you examine the return code from some_command directly, with no intermediary bash process involved.

Upvotes: 2

Related Questions