Python的subprocess
模块是一个强大且灵活的工具,它允许开发者在Python脚本中启动新的进程,并与这些进程进行交互。通过subprocess
模块,你可以执行系统命令、捕获输出、处理错误,甚至管理多个进程的并行执行。本文将深入探讨subprocess
模块的核心功能和高级用法,帮助你更好地掌握这一强大的工具。
一、基本概念与常用功能
subprocess
模块允许你生成新的进程,连接到它们的输入/输出/错误管道,并获取它们的返回码。这是执行外部命令或程序时的非常有用的功能。
1.1 subprocess.run
方法
subprocess.run
是 subprocess
模块中最常用的函数之一。它用于运行一个命令并等待其完成。通过参数控制命令的输入、输出和错误流。
import subprocess
# 运行一个简单的外部命令
result = subprocess.run(['echo', 'Hello, World!'], capture_output=True, text=True)
print(result.stdout) # 输出: Hello, World!
1.2 捕获命令的输出和错误
subprocess.run
方法可以捕获命令的标准输出和标准错误。
import subprocess
# 运行一个命令并捕获输出和错误
result = subprocess.run(['ls', 'nonexistent_file'], capture_output=True, text=True)
print("stdout:", result.stdout)
print("stderr:", result.stderr)
二、实际应用
2.1 使用 subprocess.Popen
类
subprocess.Popen
类提供了更细粒度的控制,适用于更复杂的场景。你可以通过 Popen
对象与子进程进行交互,例如发送输入、读取输出和错误。
import subprocess
# 创建一个 Popen 对象
process = subprocess.Popen(['cat'], stdin=subprocess.PIPE, stdout=subprocess.PIPE, stderr=subprocess.PIPE, text=True)
# 发送输入
output, error = process.communicate(input='Hello, World!')
# 获取输出和错误
print("Output:", output)
print("Error:", error)
2.2 批量重命名文件
假设你有一个目录,里面有很多文件,你想批量将这些文件的扩展名从 .txt
改为 .md
。我们可以使用 subprocess
模块来实现这个任务。
import os
import subprocess
# 定义目录路径
directory = '/path/to/your/directory'
# 遍历目录中的所有文件
for filename in os.listdir(directory):
if filename.endswith('.txt'):
# 构建新文件名
new_filename = filename[:-4] + '.md'
# 构建完整路径
old_path = os.path.join(directory, filename)
new_path = os.path.join(directory, new_filename)
# 使用 mv 命令重命名文件
result = subprocess.run(['mv', old_path, new_path], check=True)
print(f"Renamed {old_path} to {new_path}")
三、进程管理与错误处理
3.1 错误处理与异常捕获
subprocess.run
方法可以捕获命令的错误,并在命令执行失败时处理错误。
import subprocess
try:
# 执行一个错误命令
result = subprocess.run(['nonexistent_command'], capture_output=True, text=True, check=True)
except subprocess.CalledProcessError as e:
print(f"命令执行失败,错误码: {e.returncode}")
print(f"错误信息: {e.stderr}")
3.2 超时处理
设置超时时间是确保子进程不会无限期地运行的一种方式。
import subprocess
try:
result = subprocess.run(['sleep', '10'], timeout=5, check=True)
except subprocess.TimeoutExpired:
print("Process timed out.")