98

I'm completely confused between subprocess.call() , subprocess.Popen(), subprocess.check_call().

Which is blocking and which is not ?

What I mean to say is if I use subprocess.Popen() whether the parent process waits for the child process to return/exit before it keep on its execution.

How does shell=True affect these calls?

2
  • did you try subprocess.call([cmd,params,&])? Commented Oct 24, 2017 at 19:16
  • @CharlieParker the & would have to be in quotation marks, and the params would have to be separate elements of the list, and it would have to use shell=True, and actually it should actually use a string instead of a pre-parsed list. It does work, but it's a hack. Commented May 8, 2023 at 14:11

1 Answer 1

130

Popen is nonblocking. call and check_call are blocking. You can make the Popen instance block by calling its wait or communicate method.

If you look in the source code, you'll see call calls Popen(...).wait(), which is why it is blocking. check_call calls call, which is why it blocks as well.

Strictly speaking, shell=True is orthogonal to the issue of blocking. However, shell=True causes Python to exec a shell and then run the command in the shell. If you use a blocking call, the call will return when the shell finishes. Since the shell may spawn a subprocess to run the command, the shell may finish before the spawned subprocess. For example,

import subprocess
import time

proc = subprocess.Popen('ls -lRa /', shell=True)
time.sleep(3)
proc.terminate()
proc.wait()

Here two processes are spawned: Popen spawns one subprocess running the shell. The shell in turn spawns a subprocess running ls. proc.terminate() kills the shell, but the subprocess running ls remains. (That is manifested by copious output, even after the python script has ended. Be prepared to kill the ls with pkill ls.)

Sign up to request clarification or add additional context in comments.

11 Comments

@dotslash: shell=True can be a security hazard if the command comes from user input. So it is better to use shell=False if possible. With shell=False, supply the command and its arguments in a list: proc = subprocess.Popen(['/run_python.py', '-n', '10'], shell=False).
@dotslash: Popen is always non-blocking. It is calling wait or communicate which blocks.
what is wrong with using subprocess.call([cmd,params,&])? i.e. adding the standard &?
so if i would like to use shell=True and i would like it to block the execution until the inner process of the shell ends, how could i do it?
|

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.