Python 3.x 中如何使用subprocess模块执行外部命令

1. 简介

Python作为一门高级编程语言,提供了大量的模块方便了开发者的工作。其中一个非常有用的模块就是subprocess。它提供了一种方便的方法以子进程的方式执行外部命令。此模块可以方便地启动新的进程,并在脚本中与其进行交互。

2. subprocess的基本使用

下面是一个简单的subprocess实例,它执行了外部命令ls:

import subprocess

subprocess.call(["ls", "-l"])

输出结果:

total 0

-rw-r--r-- 1 root root 0 Aug 22 07:22 file1.txt

-rw-r--r-- 1 root root 0 Aug 22 07:22 file2.txt

-rw-r--r-- 1 root root 0 Aug 22 07:22 file3.txt

同时,我们还可以从stdin、stdout、stderr这三个对象中读取和写入数据。例如,我们可以使用Popen对象启动进程,并读取其output和error数据:

from subprocess import Popen, PIPE

process = Popen(['ls', '-al'], stdout=PIPE, stderr=PIPE)

stdout, stderr = process.communicate()

print(stdout, stderr)

此代码以上述方式输出ls的stdout和stderr结果。-a参数是显示全部文件及目录,-l参数是显示详细信息。

3. 使用subprocess.call()

3.1 基本使用方法

subprocess.call语法如下:

subprocess.call(args, *, stdin=None, stdout=None, stderr=None, shell=False, timeout=None)

args是外部命令参数的列表。如果你需要在命令行中执行的外部命令是“ls -l”,那么你可以使用以下代码:

subprocess.call(["ls", "-l"])

3.2 在Windows系统中使用call()

如果您在Windows系统上使用subprocess.call(),则调用应像下面这样:

subprocess.call(["dir"])

您还可以指定Shell选项来运行.bat或.cmd文件:

subprocess.call("my_script.bat", shell=True)

3.3 使用call()的返回值

subprocess.call()函数的返回值是命令的退出代码。如果命令成功执行,则返回0,否则返回错误代码。您可以根据返回值检查命令是否执行成功。

4. 使用subprocess.Popen()

4.1 基本使用方法

subprocess模块中Popen类允许我们在不阻塞主程序的情况下启动一个新进程。语法如下:

p = subprocess.Popen(args, stdout=subprocess.PIPE)

这将启动一个新进程,并在args参数中指定的文件上执行新进程。这种方法可以防止主程序被阻塞,直到新进程完成。此外,您还可以指定新进程的输入、输出和错误流并连接到Python程序。您可以使用以下代码来实现:

import subprocess

p1 = subprocess.Popen(["ls"], stdout=subprocess.PIPE)

p2 = subprocess.Popen(["grep", "txt"], stdin=p1.stdout,stdout=subprocess.PIPE)

p1.stdout.close()

output = p2.communicate()[0]

print(output)

以上代码列出当前目录中包含“txt”文件的所有文件。在此示例中,Popen对象p1列出目录中的所有文件,而Popen对象p2过滤p1对象的输出,并仅显示包含“txt”的文件。

4.2 使用PIPE进行I/O操作

Popen类提供了各种方法,例如communicate()、send()、recv()等,可用于从外部命令的stdin、stdout和stderr中读取和写入数据。

proc = subprocess.Popen(['ls', '-alh'], stdout=subprocess.PIPE, shell=True)

(out, err) = proc.communicate()

print(out)

在此示例中,我们使用PIPE作为stdout参数。这是因为,我们需要从ls命令的输出中获取数据并将其打印到屏幕上。communicate()方法用于从管道中读取输出,并等待进程结束。

4.3 将数据写入外部命令的stdin

您可以使用Popen对象的stdin属性将数据写入到外部命令的stdin中。以下代码展示了如何向外部命令“cat”中写入数据:

from subprocess import Popen, PIPE

p1 = Popen(["cat"], stdin=PIPE, stdout=PIPE)

output = p1.communicate(input=b'hello world')[0]

print(output)

此代码中,我们使用Popen对象p1,并指定stdin参数。然后我们将数据写入stdin并调用communicate()方法。注意,在此示例中,我们需要将输入数据转换为字节数组,因为stdin属性期望在字节上写入数据。

4.4 异步执行进程

您可以使用 Popen 方法并指定各种关键字参数来异步执行进程,例如 stdout, stderr, shell 等。以下是异步执行进程的示例代码:

import subprocess

import time

# 异步执行 ping 命令

ping = subprocess.Popen(["ping","-c", "5", "www.google.com"], stdout=subprocess.PIPE, stderr=subprocess.PIPE, shell=False)

# 稍做延时

time.sleep(1)

# 如果进程状态仍是 None,则表示进程仍未结束

if ping.poll() is None:

print("Ping command is still running.")

# 等待进程结束,并获取进程信息

ping.wait()

# 获取命令结果

(out, err) = ping.communicate()

# 打印输出结果

print(out)

在上面的代码中,我们使用了 Popen 方法并指定了一些关键字参数,包括 stdout 和 stderr。由于我们在指定了stdout和stderr后未指定PIPE选项,因此在脚本的后续部分中不再捕获输出和错误信息。为了异步执行该命令,我们使用了sleep()函数,然后我们检查进程的状态,如果它仍是None,那么我们输出一个消息并等待进程结束。在等待进程结束时,我们使用了wait()方法。最后,我们使用communicate()方法获取输出结果并打印它。

总结

Python subprocess模块为在Python中执行外部命令提供了一个容易而有效的方法。您可以轻松地启动新进程并与其进行交互。不过,当您使用subprocess模块时,请注意一些安全问题。例如,避免在命令字符串中使用shell=True选项,以防止被不良用户以各种方式利用您的脚本。总体而言,subprocess模块是Python生态系统中的一个极好的工具,易于使用而且非常灵活。

后端开发标签