1. 简介
subprocess
是Python标准库中的模块,用于在Python程序中启动新的外部进程并与它们进行交互。这个模块提供了多种方法来执行外部命令,捕获命令的输出,处理标准输入和输出,以及管理进程的各个方面。以下是subprocess模块的一些关键功能和用途:
- 执行外部命令:
subprocess
模块允许您在Python程序中执行外部命令,就像在命令行中执行一样。您可以指定要执行的命令以及任何参数。 - 捕获输出:您可以捕获外部命令的标准输出和标准错误输出,以便在Python中进一步处理或分析结果。
- 处理标准输入/输出:
subprocess
允许您将数据传递给外部进程的标准输入,也允许您从标准输出和标准错误输出中读取数据。这对于与外部进程进行交互非常有用。 - 等待命令完成:您可以选择等待外部命令完成或不等待,并在后台执行命令。
- 进程管理:
subprocess
提供了方法来获取和管理子进程的各种信息,如进程ID、状态、返回码等。 - 跨平台:
subprocess
模块在不同的操作系统上都能工作,因此它是跨平台的解决方案。 - 异常处理:
subprocess
模块可以处理与命令执行相关的异常,包括命令未找到、命令执行失败等情况。
subprocess
模块是在Python中执行外部命令和与外部进程进行交互的关键工具之一。无论是执行命令行工具、处理数据流,还是管理外部进程,subprocess
都能帮助您轻松完成这些任务。
2. subprocess.run
subprocess.run
是一个高级接口,用于执行外部命令并等待其完成。相较于 subprocess.Popen
,subprocess.run
的控制能力更有限,通常适用于简单的命令执行和获取结果的场景
2.1 应用场景
subprocess.run()
是Python 3.5及更高版本中subprocess
模块引入的函数,用于执行外部命令。
它的应用场景非常广泛,特别适用于以下情况:
- 执行外部命令:您可以使用
subprocess.run()
来执行系统中的外部命令,如调用其他可执行程序、脚本或工具。这可以用于自动化任务、系统管理和批处理作业等。 - 获取命令的标准输出和错误输出:
subprocess.run()
允许您捕获命令的标准输出和错误输出,以便进一步处理或记录执行结果。 - 等待命令完成返回结果:
subprocess.run()
会等待命令执行完成,然后返回一个包含有关执行结果的CompletedProcess
对象,其中包括命令的返回码和执行时间等信息。 - 控制执行环境:您可以设置执行命令的工作目录、环境变量和输入数据。这使您可以在特定环境中运行命令,以及向命令提供输入数据。
- 安全执行命令:
subprocess.run()
提供了一种更安全的方式来执行外部命令,它不依赖于系统shell,并且能够避免一些潜在的安全风险,如命令注入攻击。 - 异常处理:
subprocess.run()
会引发异常,以便您可以捕获和处理命令执行期间可能发生的错误,如命令未找到或执行失败等情况。
2.2 常用参数
subprocess.run()
函数有许多参数,用于控制执行外部命令的各个方面。下面是对这些参数的简要介绍:
args
(必需):要执行的命令及其参数,可以是一个字符串或一个包含命令和参数的列表、元组。stdin
:用于输入数据的文件对象。如果不指定,输入数据可以通过input
参数传递。input
:要传递给命令的输入数据,通常是一个字符串。如果指定了stdin
参数,则input
会被忽略。stdout
:用于捕获命令的标准输出的文件对象。如果不指定,可以使用capture_output=True
来捕获输出。stderr
:用于捕获命令的标准错误输出的文件对象。如果不指定,可以使用capture_output=True
来捕获输出。capture_output
:一个布尔值,用于指示是否捕获命令的标准输出和标准错误输出。如果为True
,stdout
和stderr
参数会自动设置为subprocess.PIPE
,以便捕获输出。shell
:一个布尔值,用于指示是否通过系统shell来执行命令。默认为False
,即不通过系统shell。cwd
:要执行命令的工作目录。如果不指定,命令将在当前工作目录中执行。timeout
:命令的最大运行时间(以秒为单位)。如果命令在超时之前未完成,则会引发TimeoutExpired
异常。check
:一个布尔值,用于指示是否在命令返回非零退出代码时引发CalledProcessError
异常。默认为False,即不引发异常。- 返回值returncode,正常check=True时 returncode=0 代表结果都输出正常
encoding
:要用于解码命令的标准输出和标准错误输出的编码。errors
:用于解码命令的标准输出和标准错误输出的错误处理方法。text
:一个布尔值,用于指示是否以文本模式打开标准输入、标准输出和标准错误。如果为True
,则stdin
、stdout
和stderr
会自动以文本模式打开。env
:要传递给命令的环境变量字典。universal_newlines
:在Python 3中已废弃。在Python 2中,它指示是否以通用换行符模式打开标准输入、标准输出和标准错误。
2.3 示例
- 获取输出
import subprocess
# 静默执行命令,禁用命令的标准输出
# result = subprocess.run(["ls", "-l"], cwd='/tmp', stdout=subprocess.DEVNULL)
# 不捕获输出,直接显示在终端
# result = subprocess.run(["ls", "-l"])
# 执行命令并捕获标准输出
result = subprocess.run(["ls", "-l"], cwd='/tmp', stdout=subprocess.PIPE, text=True)
# 获取命令的标准输出,执行结果
print(result.stdout)
print(result.returncode)
# 执行命令并捕获标准输出,标准错误输出
result = subprocess.run(["ls", "-l"], cwd='/tmp', capture_output=True, text=True)
# 将标准输出和标准错误输出重定向到文件output.txt和error.txt
with open("output.txt", "w") as stdout_file, open("error.txt", "w") as stderr_file:
result = subprocess.run(["ls", "/tmp"], stdout=stdout_file, stderr=stderr_file, text=True)
- 根据不同命令执行结果输出不同颜色的结果
import subprocess
from colorama import Fore, init
# 初始化Colorama
init(autoreset=True)
def run_command(command, cwd=None, encoding=None):
try:
# 执行命令,捕获标准输出和返回码
result = subprocess.run(command, cwd=cwd, shell=False, encoding=encoding, capture_output=True)
# 如果命令成功执行,返回码为0,输出绿色文本
if result.returncode == 0:
print(Fore.GREEN + "Command executed successfully.")
print(result.stdout)
else:
# 如果命令执行失败,返回码非0,输出红色文本
print(Fore.RED + f"Command failed with return code {result.returncode}")
print(result.stderr)
except Exception as e:
# 发生异常时输出黄色文本,并打印异常信息
print(Fore.YELLOW + f"An error occurred: {str(e)}")
exit(123)
# 调用优化后的函数来执行命令并显示不同颜色的文本
cmd = 'systeminfo'
enc = 'gbk'
run_command(command=cmd, encoding=enc)
3. subprocess.Popen
大多数情况下,推荐使用run()
方法调用子进程,执行操作系统命令。在更高级的使用场景,你还可以使用 Popen
接口。其实run()
方法在底层调用的就是 Popen
接口。
3.1 应用场景
subprocess.Popen
在以下场景中非常有用:
- 实时数据获取:如果您需要实时获取正在执行的命令的输出,
subprocess.Popen
允许您在命令执行时逐行或逐块获取标准输出和标准错误输出。 - 并行执行多个命令:使用
subprocess.Popen
,您可以同时启动多个子进程来执行不同的命令,而不需要等待一个命令完成后再执行另一个。 - 实时监控和处理命令输出:适用于需要监控命令的输出并基于输出采取实时措施的应用,例如日志记录、数据流处理等。
- 与正在运行的进程进行交互:如果您需要与正在运行的外部进程进行交互,例如向其发送输入或从中读取输出,
subprocess.Popen
提供了管道和标准输入输出的控制。 - 执行复杂的任务:对于需要更高级的控制和管理的任务,例如长时间运行的进程、多个子进程之间的通信等,
subprocess.Popen
提供了更大的灵活性。 - 高级命令行选项:如果您需要使用高级的命令行选项,通过
subprocess.Popen
可以更灵活地构建和调整命令参数。
总之,subprocess.Popen
对于需要更高级、更精确控制的命令执行和进程管理场景非常有用。它允许您以多种方式与外部进程进行交互,并以更灵活的方式处理命令的输入和输出。
3.2 常用参数
subprocess.Popen
是一个用于创建子进程来执行外部命令的函数,它接受一系列参数,用于配置和控制子进程的行为。以下是 subprocess.Popen 的一些常见参数:
args
:一个字符串或字符串列表,包含要执行的命令及其参数。stdin
:指定子进程的标准输入,可以是一个文件对象或者subprocess.PIPE
(表示从父进程中获取输入)。stdout
:指定子进程的标准输出,可以是一个文件对象、subprocess.PIPE
(表示捕获子进程的输出)、subprocess.DEVNULL
(表示丢弃输出)、None
(继承父进程的输出)、或一个文件描述符(整数)。stderr
:指定子进程的标准错误输出,可以是一个文件对象、subprocess.PIPE
、subprocess.DEVNULL
、None
,或一个文件描述符。shell
:一个布尔值,指示是否通过shell
来执行命令。如果设置为True
,可以使用字符串形式的命令,否则应该使用字符串列表的形式。cwd
:指定子进程的工作目录,用于执行命令。env
:一个字典,用于指定子进程的环境变量。如果未指定,将使用父进程的环境变量。universal_newlines
:一个布尔值,用于指示是否在文本模式下打开标准输入、输出和错误输出。encoding
:用于解码标准输出和标准错误输出的字符编码。errors
:用于处理解码错误的方式,通常为strict
、ignore
或replace
。close_fds
:一个布尔值,指示是否在子进程启动时关闭所有文件描述符。- 其他参数:还有其他参数,如
preexec_fn
、startupinfo
、creationflags
等,用于进一步控制子进程的行为。
3.3 方法
subprocess.Popen
是 subprocess
模块提供的用于创建子进程的函数,它返回一个表示新进程的对象,允许你与该进程进行交互、控制其行为和处理其输入输出。下面是一些常用的 subprocess.Popen
方法和属性:
communicate(input=None)
:这个方法用于与子进程交互,它将输入数据传递给子进程的标准输入,然后等待子进程完成,并返回一个包含标准输出和标准错误输出的元组。你可以通过传递 input 参数来提供标准输入的数据。wait()
:wait 方法用于等待子进程完成,然后返回子进程的返回码(退出状态码)。poll()
:poll 方法检查子进程是否已经结束。如果子进程已经结束,它返回子进程的返回码;如果子进程仍在运行,它返回 None。terminate()
:terminate 方法用于发送 SIGTERM 信号给子进程,以请求其终止。这通常用于正常终止进程。kill()
:kill 方法用于发送 SIGKILL 信号给子进程,以强制其立即终止。这通常用于异常情况下的进程终止。send_signal(signal)
:send_signal 方法用于发送任意信号给子进程。你可以通过这个方法发送其他信号,而不仅仅是 SIGTERM 或 SIGKILL。stdout
和stderr
:这些属性分别用于获取子进程的标准输出和标准错误输出。你可以从中读取子进程的输出数据。stdin
:这个属性用于获取子进程的标准输入。你可以将数据写入这个文件对象,以提供标准输入的数据。returncode
:这个属性用于获取子进程的返回码,表示子进程的退出状态码。
这些方法和属性允许你与子进程进行交互、等待其完成以及获取其输出和状态信息。根据你的需求,你可以使用这些方法来管理子进程的行为。
3.4 示例
- 实时数据处理和监控:当需要实时处理外部命令的输出或监控正在执行的进程时,
subprocess.Popen
非常有用。例如,监视服务器日志文件、实时数据处理、或实时获取命令行工具的输出。
import subprocess
# ping连通性后将结果输出
process = subprocess.Popen('ping www.baidu.com', shell=False, stdout=subprocess.PIPE, encoding='gbk')
# 从管道获取结果并输出
while True:
res = process.stdout.readline()
if not res:
break
print(res)
# 等待命令执行完毕并获取返回码
return_code = process.wait()
print("Command executed with return code:", return_code)
-----------------------------------------------------------------
import subprocess
# 启动并实时监控一个命令的输出
process = subprocess.Popen("tail -f /var/log/server.log", shell=True, stdout=subprocess.PIPE)
for line in process.stdout:
print(line.decode("utf-8").strip())
- 批处理任务:如果需要按顺序执行一系列命令,并根据前一个命令的输出来决定下一个命令的操作,
subprocess.Popen
可以帮助你实现这种批处理任务。
import subprocess
# 依次执行多个命令
commands = ["command1", "command2", "command3"]
for cmd in commands:
subprocess.Popen(cmd, shell=True).wait()
- 与外部工具的集成:当需要与外部工具或服务进行交互时,subprocess.Popen可以用来启动和控制这些工具,以便与它们进行通信。
import subprocess
# 启动一个Python脚本并与其交互
process = subprocess.Popen(["python", "my_script.py"], stdin=subprocess.PIPE, stdout=subprocess.PIPE)
output, _ = process.communicate(input="some_input".encode("utf-8"))
print(output.decode("utf-8"))
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· Manus重磅发布:全球首款通用AI代理技术深度解析与实战指南
· 被坑几百块钱后,我竟然真的恢复了删除的微信聊天记录!
· 没有Manus邀请码?试试免邀请码的MGX或者开源的OpenManus吧
· 园子的第一款AI主题卫衣上架——"HELLO! HOW CAN I ASSIST YOU TODAY
· 【自荐】一款简洁、开源的在线白板工具 Drawnix