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生态系统中的一个极好的工具,易于使用而且非常灵活。