The definition of subprocess.call() clearly mentions:
It is equivalent to:
run(...).returncode(except that the input and check parameters are not supported)
As the Python 3.5's subprocess document says:
Prior to Python 3.5, these three functions (i.e.
.call(),.check_call(),.check_output()) comprised the high level API to subprocess. You can now userun()in many cases, but lots of existing code calls these functions.
It is a common practice that when some functions are replaced, they are not instantly deprecated but there is a support window for them for some versions. This helps in preventing the breakage of older code when the language version is upgraded. I do not know whether .call() is going to be replaced in the future or not. But based on the document, what I know is that they are pretty much same.
The definition of subprocess.call() clearly mentions:
It is equivalent to:
run(...).returncode(except that the input and check parameters are not supported)
As the Python 3.5's subprocess document says:
Prior to Python 3.5, these three functions (i.e.
.call(),.check_call(),.check_output()) comprised the high level API to subprocess. You can now userun()in many cases, but lots of existing code calls these functions.
It is a common practice that when some functions are replaced, they are not instantly deprecated but there is a support window for them for some versions. This helps in preventing the breakage of older code when the language version is upgraded. I do not know whether .call() is going to be replaced in the future or not. But based on the document, what I know is that they are pretty much same.
To make it clear for anyone wanting to know which to use:
subprocess.run() is the recommended approach for all use cases it can handle. The suprocess documentation states:
The recommended approach to invoking subprocesses is to use the run() function for all use cases it can handle. For more advanced use cases, the underlying Popen interface can be used directly.
subprocess.call() is part of the Older high-level API (Prior to Python 3.5).
os.popen vs subprocess.run for simple commands
About 13 years ago, the older, deprecated per-os popen2/popen3/popen4 calls were removed, and os.popen() was implemented in terms of subprocess.Popen (just like subprocess.run is).:
https://github.com/python/cpython/commit/c2f93dc2e42b48a20578599407b0bb51a6663d09#diff-405b29928f2a3ae216e45afe9b5d0c60
So, I don't think the current os.popen() is deprecated anymore (I can't see any indication that it is; that was for the older versions which were removed).
Therefore, I think you can safely use it if you want. But, keep in mind that the popen() concept was pretty Unix specific, and isn't obvious to everyone that it's running a subprocess, whereas that should be fairly obvious from subprocess.run().
You could consider making a dictionary of keyword args (that you re-use), and passing that to subprocess.run(), if it's just the length of the calling lines that is concerning you:
runargs = {'shell': True, 'capture_output': True, 'text': True }
output = subprocess.run('<command>', **runargs).stdout More on reddit.com python - What is the difference between subprocess.popen and subprocess.run - Stack Overflow
python - What's the difference between subprocess Popen and call (how can I use them)? - Stack Overflow
How subprocess run() works?
What does subprocess run do?
Is subprocess a standard Python library?
Videos
For scripts where I've had to run shell commands and get their output, I have used subprocess.run() as I have read that it is the recommended way of running shell commands. However, I have just learned of os.popen() which seems much simpler to use if you don't need any of the extra functionality of subprocess, as shown below:
output = os.popen('<command>').read()vs
output = subprocess.run('<command>', shell=True, capture_output=True, text=True).stdoutIf I don't need any of subprocess's extra functionalities, is there any reason for me not to use os.popen() for this simple use case? Any hidden, under-the-hood reasons?
I ask this because popen is labelled as deprecated and everywhere recommends subprocess instead. Thanks in advance.
About 13 years ago, the older, deprecated per-os popen2/popen3/popen4 calls were removed, and os.popen() was implemented in terms of subprocess.Popen (just like subprocess.run is).:
https://github.com/python/cpython/commit/c2f93dc2e42b48a20578599407b0bb51a6663d09#diff-405b29928f2a3ae216e45afe9b5d0c60
So, I don't think the current os.popen() is deprecated anymore (I can't see any indication that it is; that was for the older versions which were removed).
Therefore, I think you can safely use it if you want. But, keep in mind that the popen() concept was pretty Unix specific, and isn't obvious to everyone that it's running a subprocess, whereas that should be fairly obvious from subprocess.run().
You could consider making a dictionary of keyword args (that you re-use), and passing that to subprocess.run(), if it's just the length of the calling lines that is concerning you:
runargs = {'shell': True, 'capture_output': True, 'text': True }
output = subprocess.run('<command>', **runargs).stdout
I'll still use popen here and there....
Use it with yield for best results
>>> from os import popen
>>>
>>> def cmd_out(cmd):
... for out in popen(cmd):
... yield out
...
>>>
>>> _ = [print(result) for result in cmd_out('service --status-all')]
[ + ] acpid
[ - ] alsa-utils
[ - ] anacron
[ + ] apparmor
[ + ] apport
[ + ] avahi-daemon
[ + ] bluetooth
[ - ] console-setup.sh
[ + ] cron
[ - ] cryptdisks
[ - ] cryptdisks-early
[ + ] cups
[ + ] cups-browsed
[ + ] dbus
[ - ] dns-clean
[ + ] gdm3
[ + ] grub-common
[ - ] hwclock.sh
[ + ] irqbalance
[ + ] kerneloops
[ - ] keyboard-setup.sh
[ + ] kmod
[ + ] mpd
[ + ] network-manager
[ + ] networking
[ - ] plymouth
[ - ] plymouth-log
[ - ] pppd-dns
[ + ] procps
[ - ] rsync
[ + ] rsyslog
[ - ] saned
[ + ] sddm
[ + ] speech-dispatcher
[ - ] spice-vdagent
[ - ] ssh
[ - ] supervisor
[ - ] tor
[ + ] udev
[ + ] ufw
[ + ] unattended-upgrades
[ - ] uuidd
[ + ] virtualbox
[ + ] whoopsie
[ - ] x11-common
subprocess.run() was added in Python 3.5 as a simplification over subprocess.Popen when you just want to execute a command and wait until it finishes, but you don't want to do anything else in the mean time. For other cases, you still need to use subprocess.Popen.
The main difference is that subprocess.run() executes a command and waits for it to finish, while with subprocess.Popen you can continue doing your stuff while the process finishes and then just repeatedly call Popen.communicate() yourself to pass and receive data to your process. Secondly, subprocess.run() returns subprocess.CompletedProcess.
subprocess.run() just wraps Popen and Popen.communicate() so you don't need to make a loop to pass/receive data or wait for the process to finish.
Check the official documentation for info on which params subprocess.run() pass to Popen and communicate().
Both available in Python by default.
The recommended approach to invoking subprocesses is to use the run() function for all use cases it can handle. For more advanced use cases, the underlying Popen interface can be used directly.
-subprocess.run:
import subprocess
import sys
result = subprocess.run([sys.executable, "-c", "print('ocean')"])
-subprocess.popen: run multiple command line with subprocess, communicate method waits for the process to finish and finally prints the stdout and stderr as a tuple
EX:
import subprocess
process = subprocess.Popen(shell_cmd,
stdout = subprocess.PIPE,
stderr = subprocess.PIPE,
text = True,
shell = True
)
std_out, std_err = process.communicate()
std_out.strip(), std_err
There are two ways to do the redirect. Both apply to either subprocess.Popen or subprocess.call.
Set the keyword argument
shell = Trueorexecutable = /path/to/the/shelland specify the command just as you have it there.Since you're just redirecting the output to a file, set the keyword argument
stdout = an_open_writeable_file_objectwhere the object points to the
outputfile.
subprocess.Popen is more general than subprocess.call.
Popen doesn't block, allowing you to interact with the process while it's running, or continue with other things in your Python program. The call to Popen returns a Popen object.
call does block. While it supports all the same arguments as the Popen constructor, so you can still set the process' output, environmental variables, etc., your script waits for the program to complete, and call returns a code representing the process' exit status.
returncode = call(*args, **kwargs)
is basically the same as calling
returncode = Popen(*args, **kwargs).wait()
call is just a convenience function. It's implementation in CPython is in subprocess.py:
def call(*popenargs, timeout=None, **kwargs):
"""Run command with arguments. Wait for command to complete or
timeout, then return the returncode attribute.
The arguments are the same as for the Popen constructor. Example:
retcode = call(["ls", "-l"])
"""
with Popen(*popenargs, **kwargs) as p:
try:
return p.wait(timeout=timeout)
except:
p.kill()
p.wait()
raise
As you can see, it's a thin wrapper around Popen.
The other answer is very complete, but here is a rule of thumb:
callis blocking:call('notepad.exe') print('hello') # only executed when notepad is closedPopenis non-blocking:Popen('notepad.exe') print('hello') # immediately executed