当前位置:   article > 正文

python 运行外部程序_如何使用子流程在Python 3中运行外部程序

subprocess.calledprocesserror: command '['/usr/bin/python', '-u', 'main.py',

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计划的一部分。

介绍 (Introduction)

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 。 我们将回顾其不同用途和主要关键字参数。

先决条件 (Prerequisites)

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的编程。您可以查看以下教程以获取必要的背景信息:

运行外部程序 (Running an External Program)

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代码运行外部程序。 不过,首先,您需要将subprocesssys模块导入程序中:

  1. import subprocess
  2. import sys
  3. result = subprocess.run([sys.executable, "-c", "print('ocean')"])

If you run this, you will receive output like the following:

如果运行此命令,将收到类似以下的输出:

  1. Output
  2. 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能够在您的计算机上执行任意命令,因此恶意行为者可以使用它以意想不到的方式操纵计算机。

捕获外部程序的输出 (Capturing Output From an External Program)

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_outputtext关键字参数。

Let’s add to our previous example:

让我们添加到前面的示例中:

  1. import subprocess
  2. import sys
  3. result = subprocess.run(
  4. [sys.executable, "-c", "print('ocean')"], capture_output=True, text=True
  5. )
  6. print("stdout:", result.stdout)
  7. print("stderr:", result.stderr)

If we run this code, we’ll receive output like the following:

如果运行此代码,我们将收到类似以下的输出:

  1. Output
  2. stdout: ocean
  3. 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=Truetext=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返回一个绑定到resultsubprocess.CompletedProcess对象。 subprocess.CompletedProcess对象包含有关外部程序的退出代码及其输出的详细信息。 capture_output=True确保使用外部程序的相应输出填充result.stdoutresult.stderr 。 默认情况下, result.stdoutresult.stderr绑定为字节,但是text=True关键字参数指示Python改为将字节解码为字符串。

In the output section, stdout is ocean (plus the trailing newline that print adds implicitly), and we have no stderr.

在输出部分, stdoutocean (加上print隐式添加的结尾换行符),并且我们没有stderr

Let’s try an example that produces a non-empty value for stderr:

让我们尝试一个为stderr生成非空值的示例:

  1. import subprocess
  2. import sys
  3. result = subprocess.run(
  4. [sys.executable, "-c", "raise ValueError('oops')"], capture_output=True, text=True
  5. )
  6. print("stdout:", result.stdout)
  7. print("stderr:", result.stderr)

If we run this code, we receive output like the following:

如果运行此代码,则会收到类似以下的输出:

  1. Output
  2. stdout:
  3. stderr: Traceback (most recent call last):
  4. File "<string>", line 1, in <module>
  5. 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看到ValueErrorTraceback 。 这是因为默认情况下,Python将未处理的异常的Traceback写入stderr

在错误的退出代码上引发异常 (Raising an Exception on a Bad Exit Code)

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引发异常:

  1. import subprocess
  2. import sys
  3. result = subprocess.run([sys.executable, "-c", "raise ValueError('oops')"], check=True)

If we run this code, we receive output like the following:

如果运行此代码,则会收到类似以下的输出:

  1. Output
  2. Traceback (most recent call last):
  3. File "<string>", line 1, in <module>
  4. ValueError: oops
  5. Traceback (most recent call last):
  6. File "<stdin>", line 1, in <module>
  7. File "/usr/local/lib/python3.8/subprocess.py", line 512, in run
  8. raise CalledProcessError(retcode, process.args,
  9. 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方法,我们可以调用该方法以获得类似的效果:

  1. import subprocess
  2. import sys
  3. result = subprocess.run([sys.executable, "-c", "raise ValueError('oops')"])
  4. result.check_returncode()

If we run this code, we’ll receive:

如果运行此代码,我们将收到:

  1. Output
  2. Traceback (most recent call last):
  3. File "<string>", line 1, in <module>
  4. ValueError: oops
  5. Traceback (most recent call last):
  6. File "<stdin>", line 1, in <module>
  7. File "/usr/local/lib/python3.8/subprocess.py", line 444, in check_returncode
  8. raise CalledProcessError(self.returncode, self.args, self.stdout,
  9. 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.runresult即使我们的程序以非零代码退出,我们也成功绑定了subprocess.CompletedProcess实例以result 。 但是,调用result.check_returncode()会引发subprocess.CalledProcessError因为它检测到已完成的进程已以错误代码退出。

使用超时提前退出程序 (Using timeout to Exit Programs Early)

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参数,允许您在执行时间过长时停止外部程序:

  1. import subprocess
  2. import sys
  3. 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:

如果运行此代码,我们将收到类似以下的输出:

  1. Output
  2. Traceback (most recent call last):
  3. File "<stdin>", line 1, in <module>
  4. File "/usr/local/lib/python3.8/subprocess.py", line 491, in run
  5. stdout, stderr = process.communicate(input, timeout=timeout)
  6. File "/usr/local/lib/python3.8/subprocess.py", line 1024, in communicate
  7. stdout, stderr = self._communicate(input, endtime, timeout)
  8. File "/usr/local/lib/python3.8/subprocess.py", line 1892, in _communicate
  9. self.wait(timeout=self._remaining_time(endtime))
  10. File "/usr/local/lib/python3.8/subprocess.py", line 1079, in wait
  11. return self._wait(timeout=timeout)
  12. File "/usr/local/lib/python3.8/subprocess.py", line 1796, in _wait
  13. raise TimeoutExpired(self.args, timeout)
  14. 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.runtimeout关键字参数为近似值。 在timeout秒数后,Python将尽最大努力杀死该子进程,但这不一定是准确的。

将输入传递给程序 (Passing Input to Programs)

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.runinput关键字参数允许您将数据传递到subprocess.runstdin 。 例如:

  1. import subprocess
  2. import sys
  3. result = subprocess.run(
  4. [sys.executable, "-c", "import sys; print(sys.stdin.read())"], input=b"underwater"
  5. )

We’ll receive output like the following after running this code:

运行此代码后,我们将收到如下输出:

  1. Output
  2. 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参数传递给另一个程序是很有用的。

结论 (Conclusion)

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模块的文档来了解有关其他可用类和实用程序的更多信息。

翻译自: https://www.digitalocean.com/community/tutorials/how-to-use-subprocess-to-run-external-programs-in-python-3

python 运行外部程序

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/我家自动化/article/detail/506909
推荐阅读
相关标签
  

闽ICP备14008679号