赞
踩
python 运行外部程序
The author selected the COVID-19 Relief Fund to receive a donation as part of the Write for DOnations program.
作者选择了COVID-19救济基金来接受捐赠,这是Write for DOnations计划的一部分。
Python 3 includes the subprocess
module for running external programs and reading their outputs in your Python code.
Python 3包含用于运行外部程序并读取您的Python代码中的输出的subprocess
模块 。
You might find subprocess
useful if you want to use another program on your computer from within your Python code. For example, you might want to invoke git
from within your Python code to retrieve files in your project that are tracked in git
version control. Since any program you can access on your computer can be controlled by subprocess
, the examples shown here will be applicable to any external program you might want to invoke from your Python code.
如果要从Python代码中使用计算机上的另一个程序,可能会发现subprocess
很有用。 例如,您可能想从Python代码中调用git
,以检索项目中在git
版本控制中跟踪的文件。 由于您可以在计算机上访问的任何程序都可以由subprocess
控制,因此此处显示的示例适用于您可能想从Python代码调用的任何外部程序。
subprocess
includes several classes and functions, but in this tutorial we’ll cover one of subprocess
’s most useful functions: subprocess.run
. We’ll review its different uses and main keyword arguments.
subprocess
包含几个类和函数,但是在本教程中,我们将介绍subprocess
最有用的功能之一: subprocess.run
。 我们将回顾其不同用途和主要关键字参数。
To get the most out of this tutorial, it is recommended to have some familiarity with programming in Python 3. You can review these tutorials for the necessary background information:
为了充分利用本教程,建议您熟悉Python 3的编程。您可以查看以下教程以获取必要的背景信息:
You can use the subprocess.run
function to run an external program from your Python code. First, though, you need to import the subprocess
and sys
modules into your program:
您可以使用subprocess.run
函数从Python代码运行外部程序。 不过,首先,您需要将subprocess
和sys
模块导入程序中:
- import subprocess
- import sys
-
- result = subprocess.run([sys.executable, "-c", "print('ocean')"])
If you run this, you will receive output like the following:
如果运行此命令,将收到类似以下的输出:
-
-
-
-
- Output
-
- ocean
Let’s review this example:
让我们来看这个例子:
sys.executable
is the absolute path to the Python executable that your program was originally invoked with. For example, sys.executable
might be a path like /usr/local/bin/python
.
sys.executable
是程序最初被调用的Python可执行文件的绝对路径。 例如, sys.executable
可能是/usr/local/bin/python
类的路径。
subprocess.run
is given a list of strings consisting of the components of the command we are trying to run. Since the first string we pass is sys.executable
, we are instructing subprocess.run
to execute a new Python program.
给subprocess.run
一个字符串列表,该字符串列表包含我们要运行的命令的组成部分。 因为我们通过第一个字符串是sys.executable
,我们指示subprocess.run
执行新的Python程序。
The -c
component is a python
command line option that allows you to pass a string with an entire Python program to execute. In our case, we pass a program that prints the string ocean
.
-c
组件是python
命令行选项,它允许您将字符串与整个Python程序一起传递来执行。 在我们的例子中,我们通过了一个打印字符串ocean
的程序。
You can think of each entry in the list that we pass to subprocess.run
as being separated by a space. For example, [sys.executable, "-c", "print('ocean')"]
translates roughly to /usr/local/bin/python -c "print('ocean')"
. Note that subprocess
automatically quotes the components of the command before trying to run them on the underlying operating system so that, for example, you can pass a filename that has spaces in it.
您可以认为我们传递给subprocess.run
的列表中的每个条目都由空格分隔。 例如, [sys.executable, "-c", "print('ocean')"]
大致翻译为/usr/local/bin/python -c "print('ocean')"
。 请注意,在尝试在基础操作系统上运行之前, subprocess
自动用引号将命令的组件引起,例如,您可以传递包含空格的文件名。
Warning: Never pass untrusted input to subprocess.run
. Since subprocess.run
has the ability to perform arbitrary commands on your computer, malicious actors can use it to manipulate your computer in unexpected ways.
警告:切勿将不受信任的输入传递给subprocess.run
。 由于subprocess.run
能够在您的计算机上执行任意命令,因此恶意行为者可以使用它以意想不到的方式操纵计算机。
Now that we can invoke an external program using subprocess.run
, let’s see how we can capture output from that program. For example, this process could be useful if we wanted to use git ls-files
to output all your files currently stored under version control.
现在,我们可以使用subprocess.run
调用外部程序,让我们看看如何捕获该程序的输出。 例如,如果我们想使用git ls-files
输出当前存储在版本控制下的所有文件,则此过程可能会很有用。
Note: The examples shown in this section require Python 3.7 or higher. In particular, the capture_output
and text
keyword arguments were added in Python 3.7 when it was released in June 2018.
注意:本节中显示的示例需要Python 3.7或更高版本。 特别是,在2018年6月发布的Python 3.7中添加了capture_output
和text
关键字参数。
Let’s add to our previous example:
让我们添加到前面的示例中:
- import subprocess
- import sys
-
- result = subprocess.run(
- [sys.executable, "-c", "print('ocean')"], capture_output=True, text=True
- )
- print("stdout:", result.stdout)
- print("stderr:", result.stderr)
If we run this code, we’ll receive output like the following:
如果运行此代码,我们将收到类似以下的输出:
-
-
-
-
- Output
-
- stdout: ocean
-
- stderr:
This example is largely the same as the one introduced in the first section: we are still running a subprocess to print ocean
. Importantly, however, we pass the capture_output=True
and text=True
keyword arguments to subprocess.run
.
该示例与第一部分中介绍的示例大致相同:我们仍在运行一个子进程来打印ocean
。 但是重要的是,我们将capture_output=True
和text=True
关键字参数传递给subprocess.run
。
subprocess.run
returns a subprocess.CompletedProcess
object that is bound to result
. The subprocess.CompletedProcess
object includes details about the external program’s exit code and its output. capture_output=True
ensures that result.stdout
and result.stderr
are filled in with the corresponding output from the external program. By default, result.stdout
and result.stderr
are bound as bytes, but the text=True
keyword argument instructs Python to instead decode the bytes into strings.
subprocess.run
返回一个绑定到result
的subprocess.CompletedProcess
对象。 subprocess.CompletedProcess
对象包含有关外部程序的退出代码及其输出的详细信息。 capture_output=True
确保使用外部程序的相应输出填充result.stdout
和result.stderr
。 默认情况下, result.stdout
和result.stderr
绑定为字节,但是text=True
关键字参数指示Python改为将字节解码为字符串。
In the output section, stdout
is ocean
(plus the trailing newline that print
adds implicitly), and we have no stderr
.
在输出部分, stdout
是ocean
(加上print
隐式添加的结尾换行符),并且我们没有stderr
。
Let’s try an example that produces a non-empty value for stderr
:
让我们尝试一个为stderr
生成非空值的示例:
- import subprocess
- import sys
-
- result = subprocess.run(
- [sys.executable, "-c", "raise ValueError('oops')"], capture_output=True, text=True
- )
- print("stdout:", result.stdout)
- print("stderr:", result.stderr)
If we run this code, we receive output like the following:
如果运行此代码,则会收到类似以下的输出:
-
-
-
-
- Output
-
- stdout:
- stderr: Traceback (most recent call last):
- File "<string>", line 1, in <module>
- ValueError: oops
-
This code runs a Python subprocess that immediately raises a ValueError
. When we inspect the final result
, we see nothing in stdout
and a Traceback
of our ValueError
in stderr
. This is because by default Python writes the Traceback
of the unhandled exception to stderr
.
此代码运行一个Python子进程,该子进程立即引发ValueError
。 当检查最终result
,在stdout
中看不到任何东西,而在stderr
看到ValueError
的Traceback
。 这是因为默认情况下,Python将未处理的异常的Traceback
写入stderr
。
Sometimes it’s useful to raise an exception if a program we run exits with a bad exit code. Programs that exit with a zero code are considered successful, but programs that exit with a non-zero code are considered to have encountered an error. As an example, this pattern could be useful if we wanted to raise an exception in the event that we run git ls-files
in a directory that wasn’t actually a git
repository.
如果我们运行的程序退出时退出代码错误,有时引发异常很有用。 以零代码退出的程序被视为成功,但是以非零代码退出的程序被视为遇到错误。 例如,如果我们想在实际不是git
存储库的目录中运行git ls-files
时引发异常,则此模式可能很有用。
We can use the check=True
keyword argument to subprocess.run
to have an exception raised if the external program returns a non-zero exit code:
如果外部程序返回一个非零的退出代码,我们可以使用check=True
关键字参数subprocess.run
引发异常:
- import subprocess
- import sys
-
- result = subprocess.run([sys.executable, "-c", "raise ValueError('oops')"], check=True)
If we run this code, we receive output like the following:
如果运行此代码,则会收到类似以下的输出:
-
-
-
-
- Output
-
- Traceback (most recent call last):
- File "<string>", line 1, in <module>
- ValueError: oops
- Traceback (most recent call last):
- File "<stdin>", line 1, in <module>
- File "/usr/local/lib/python3.8/subprocess.py", line 512, in run
- raise CalledProcessError(retcode, process.args,
- subprocess.CalledProcessError: Command '['/usr/local/bin/python', '-c', "raise ValueError('oops')"]' returned non-zero exit status 1.
This output shows that we ran a subprocess that raised an error, which is printed in stderr
in our terminal. Then subprocess.run
dutifully raised a subprocess.CalledProcessError
on our behalf in our main Python program.
此输出表明我们运行了一个引发错误的子进程,该子进程打印在终端的stderr
中。 然后subprocess.run
代表我们在主Python程序中忠实地提出了subprocess.CalledProcessError
。
Alternatively, the subprocess
module also includes the subprocess.CompletedProcess.check_returncode
method, which we can invoke for similar effect:
另外, subprocess
模块还包括subprocess.CompletedProcess.check_returncode
方法,我们可以调用该方法以获得类似的效果:
- import subprocess
- import sys
-
- result = subprocess.run([sys.executable, "-c", "raise ValueError('oops')"])
- result.check_returncode()
If we run this code, we’ll receive:
如果运行此代码,我们将收到:
-
-
-
-
- Output
-
- Traceback (most recent call last):
- File "<string>", line 1, in <module>
- ValueError: oops
- Traceback (most recent call last):
- File "<stdin>", line 1, in <module>
- File "/usr/local/lib/python3.8/subprocess.py", line 444, in check_returncode
- raise CalledProcessError(self.returncode, self.args, self.stdout,
- subprocess.CalledProcessError: Command '['/usr/local/bin/python', '-c', "raise ValueError('oops')"]' returned non-zero exit status 1.
Since we didn’t pass check=True
to subprocess.run
, we successfully bound a subprocess.CompletedProcess
instance to result
even though our program exited with a non-zero code. Calling result.check_returncode()
, however, raises a subprocess.CalledProcessError
because it detects the completed process exited with a bad code.
因为我们没有将check=True
传递给subprocess.run
, result
即使我们的程序以非零代码退出,我们也成功绑定了subprocess.CompletedProcess
实例以result
。 但是,调用result.check_returncode()
会引发subprocess.CalledProcessError
因为它检测到已完成的进程已以错误代码退出。
subprocess.run
includes the timeout
argument to allow you to stop an external program if it is taking too long to execute:
subprocess.run
包含timeout
参数,允许您在执行时间过长时停止外部程序:
- import subprocess
- import sys
-
- result = subprocess.run([sys.executable, "-c", "import time; time.sleep(2)"], timeout=1)
If we run this code, we’ll receive output like the following:
如果运行此代码,我们将收到类似以下的输出:
-
-
-
-
- Output
-
- Traceback (most recent call last):
- File "<stdin>", line 1, in <module>
- File "/usr/local/lib/python3.8/subprocess.py", line 491, in run
- stdout, stderr = process.communicate(input, timeout=timeout)
- File "/usr/local/lib/python3.8/subprocess.py", line 1024, in communicate
- stdout, stderr = self._communicate(input, endtime, timeout)
- File "/usr/local/lib/python3.8/subprocess.py", line 1892, in _communicate
- self.wait(timeout=self._remaining_time(endtime))
- File "/usr/local/lib/python3.8/subprocess.py", line 1079, in wait
- return self._wait(timeout=timeout)
- File "/usr/local/lib/python3.8/subprocess.py", line 1796, in _wait
- raise TimeoutExpired(self.args, timeout)
- subprocess.TimeoutExpired: Command '['/usr/local/bin/python', '-c', 'import time; time.sleep(2)']' timed out after 0.9997982999999522 seconds
The subprocess we tried to run used the time.sleep
function to sleep for 2
seconds. However, we passed the timeout=1
keyword argument to subprocess.run
to time out our subprocess after 1
second. This explains why our call to subprocess.run
ultimately raised a subprocess.TimeoutExpired
exception.
我们尝试运行的子进程使用time.sleep
函数Hibernate了2
秒钟。 但是,我们将timeout=1
关键字参数传递给subprocess.run
以使我们的子进程在1
秒后超时。 这解释了为什么我们对subprocess.run
的调用最终会引发subprocess.TimeoutExpired
异常。
Note that the timeout
keyword argument to subprocess.run
is approximate. Python will make a best effort to kill the subprocess after the timeout
number of seconds, but it won’t necessarily be exact.
请注意, subprocess.run
的timeout
关键字参数为近似值。 在timeout
秒数后,Python将尽最大努力杀死该子进程,但这不一定是准确的。
Sometimes programs expect input to be passed to them via stdin
.
有时程序希望输入通过stdin
传递给他们。
The input
keyword argument to subprocess.run
allows you to pass data to the stdin
of the subprocess. For example:
subprocess.run
的input
关键字参数允许您将数据传递到subprocess.run
的stdin
。 例如:
- import subprocess
- import sys
-
- result = subprocess.run(
- [sys.executable, "-c", "import sys; print(sys.stdin.read())"], input=b"underwater"
- )
We’ll receive output like the following after running this code:
运行此代码后,我们将收到如下输出:
-
-
-
-
- Output
-
- underwater
In this case, we passed the bytes underwater
to input
. Our target subprocess used sys.stdin
to read the passed in stdin
(underwater
) and printed it out in our output.
在这种情况下,我们将字节在underwater
传递给input
。 我们的目标子sys.stdin
使用sys.stdin
读取传入的stdin
( underwater
)并将其打印在输出中。
The input
keyword argument can be useful if you want to chain multiple subprocess.run
calls together passing the output of one program as the input to another.
如果要将多个subprocess.run
调用链接在一起,则将关键字的input
参数传递给另一个程序是很有用的。
The subprocess
module is a powerful part of the Python standard library that lets you run external programs and inspect their outputs easily. In this tutorial, you have learned to use subprocess.run
to control external programs, pass input to them, parse their output, and check their return codes.
subprocess
模块是Python标准库的强大功能,可让您运行外部程序并轻松检查其输出。 在本教程中,您学习了使用subprocess.run
来控制外部程序,将输入传递给它们,解析其输出以及检查其返回码。
The subprocess
module exposes additional classes and utilities that we did not cover in this tutorial. Now that you have a baseline, you can use the subprocess
module’s documentation to learn more about other available classes and utilities.
subprocess
模块提供了我们在本教程中未涵盖的其他类和实用程序。 有了基准后,就可以使用subprocess
模块的文档来了解有关其他可用类和实用程序的更多信息。
python 运行外部程序
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。