How can I call an external command (as if I'd typed it at the Unix shell or Windows command prompt) from within a Python script?
相关问题
- how to define constructor for Python's new Nam
- streaming md5sum of contents of a large remote tar
- How to get the background from multiple images by
- How to get the return code of a shell script in lu
- Evil ctypes hack in python
os.system
is OK, but kind of dated. It's also not very secure. Instead, trysubprocess
.subprocess
does not call sh directly and is therefore more secure thanos.system
.Get more information here.
https://docs.python.org/2/library/subprocess.html
...or for a very simple command:
Note that this is dangerous, since the command isn't cleaned. I leave it up to you to google for the relevant documentation on the 'os' and 'sys' modules. There are a bunch of functions (exec* and spawn*) that will do similar things.
Check the "pexpect" Python library, too.
It allows for interactive controlling of external programs/commands, even ssh, ftp, telnet, etc. You can just type something like:
Simple, use
subprocess.run
, which returns aCompletedProcess
object:Why?
As of Python 3.5, the documentation recommends subprocess.run:
Here's an example of the simplest possible usage - and it does exactly as asked:
run
waits for the command to successfully finish, then returns aCompletedProcess
object. It may instead raiseTimeoutExpired
(if you give it atimeout=
argument) orCalledProcessError
(if it fails and you passcheck=True
).As you might infer from the above example, stdout and stderr both get piped to your own stdout and stderr by default.
We can inspect the returned object and see the command that was given and the returncode:
Capturing output
If you want to capture the output, you can pass
subprocess.PIPE
to the appropriatestderr
orstdout
:(I find it interesting and slightly counterintuitive that the version info gets put to stderr instead of stdout.)
Pass a command list
One might easily move from manually providing a command string (like the question suggests) to providing a string built programmatically. Don't build strings programmatically. This is a potential security issue. It's better to assume you don't trust the input.
Note, only
args
should be passed positionally.Full Signature
Here's the actual signature in the source and as shown by
help(run)
:The
popenargs
andkwargs
are given to thePopen
constructor.input
can be a string of bytes (or unicode, if specify encoding oruniversal_newlines=True
) that will be piped to the subprocess's stdin.The documentation describes
timeout=
andcheck=True
better than I could:and this example for
check=True
is better than one I could come up with:Expanded Signature
Here's an expanded signature, as given in the documentation:
Note that this indicates that only the args list should be passed positionally. So pass the remaining arguments as keyword arguments.
Popen
When use
Popen
instead? I would struggle to find use-case based on the arguments alone. Direct usage ofPopen
would, however, give you access to its methods, includingpoll
, 'send_signal', 'terminate', and 'wait'.Here's the
Popen
signature as given in the source. I think this is the most precise encapsulation of the information (as opposed tohelp(Popen)
):But more informative is the
Popen
documentation:Understanding the remaining documentation on
Popen
will be left as an exercise for the reader.With Standard Library
The Use subprocess module (Python 3):
It is the recommended standard way. However, more complicated tasks (pipes, output, input, etc.) can be tedious to construct and write.
Note on Python version: If you are still using Python 2, subprocess.call works in a similar way.
ProTip: shlex.split can help you to parse the command for
run
,call
, and othersubprocess
functions in case you don't want (or you can't!) provide them in form of lists:With External Dependencies
If you do not mind external dependencies, use plumbum:
It is the best
subprocess
wrapper. It's cross-platform, i.e. it works on both Windows and Unix-like systems. Install bypip install plumbum
.Another popular library is sh:
However,
sh
dropped Windows support, so it's not as awesome as it used to be. Install bypip install sh
.