Skip to content

Python difference on subprocess run(), call(), check_call(), check_output()#

Difference on subprocess run(), call(), check_call(), check_output()#

Since Python 3.5, the official doc explains that:

Prior to Python 3.5, these three functions (subprocess.call(), subprocess.check_call(), subprocess.check_output()) comprised the high level API to subprocess. You can now use subprocess.run() in many cases, but lots of existing code calls these functions.

subprocess.run common parameters#

  • subprocess.run default behavior accepts arguments in list
subprocess.run(["ls", "-l"])
  • shell=True (default False) to send arguments in string
subprocess.run("ls -l", shell=True)
  • capture_output=True (default False) to save output in a var
res = subprocess.run("ls -l", shell=True, capture_output=True)
res.stdout
  • encoding="utf-8" (default None) to save var in string instead of bytes.

  • check=True (default False) to raise subprocess.CalledProcessError: if command returned non-zero exit code. But if the command executable doesn't exist for exampel missspellm you will get the error FileNotFoundError

  • Popen() is for advanced usage. For example, replacing the shell pipeline.

shell command:

output=$(dmesg | grep hda)

with Popen, becomes:

p1 = Popen(["dmesg"], stdout=PIPE)
p2 = Popen(["grep", "hda"], stdin=p1.stdout, stdout=PIPE)
p1.stdout.close()  # Allow p1 to receive a SIGPIPE if p2 exits.
output = p2.communicate()[0]
  • default params
import subprocess

default_run_params = dict(
    capture_output=True,
    encoding="utf-8",
    check=True
)
# command = ["unknown_command", "-l"]
# command = ["python", "-askjd"]
command = ["ls", "-l"]

try:
    # output type is subprocess.CompletedProcess
    output = subprocess.run(command, **default_run_params)

    # print in pure string in one line
    print(output)

    # print with new line just as launching from shell
    print(output.stdout)

    # as we catch error with `check=True`,
    # output.stderr is always an empty string.
    # and output.returncode is always 0 in this case.
except FileNotFoundError as exc:
    print(f"{type(exc).__name__}: {exc}")
    raise
except subprocess.CalledProcessError as exc:
    print(exc)  # no error details will given by print(exc)
    print(exc.__dict__)  # print all
    print(exc.returncode)
    print(exc.stderr)  # print error message only
    # exc.stdout should be empty
    raise

Comments