
Python subprocess用法
Python 的 subprocess 模块用于生成新进程,连接到它们的输入和输出,以及获取它们的返回码。它可以替代许多其他模块,比如 os.system, os.spawn, os.popen等,提供了更灵活的接口和功能。
任务概述
本文将详细讲解如何使用 subprocess 模块执行外部命令,捕获输出,以及处理异常。我们将通过多个示例展示各种用法,解析每个功能,并提供注意事项和实用技巧。
基本概念
- 创建子进程: 使用 subprocess,可以轻松创建和管理子进程。
- 执行命令: 可以执行任何 shell 命令,并捕获其输出。
- 两个重要的函数:
subprocess.run()和subprocess.Popen()。
subprocess.run() 函数
subprocess.run() 是 Python 3.5 引入的函数,它简化了创建子进程并等待其完成的过程。
基本用法
执行基本命令的示例:
import subprocess
result = subprocess.run(['ls', '-l'], capture_output=True, text=True)
print(result.stdout)
在上述示例中:
- 我们调用了
ls -l命令。 - capture_output=True 表示捕获标准输出和标准错误。
- text=True 表示输出为字符串而不是字节。
- 输出结果通过
result.stdout获取。
处理返回码
返回码可以通过 result.returncode 来访问,0 表示执行成功,其他值表示失败。
if result.returncode == 0:
print("Command executed successfully")
else:
print(f"Error occurred: {result.returncode}")
subprocess.Popen() 函数
subprocess.Popen() 提供了更底层的接口,允许对进程的输入、输出和错误流进行更复杂的控制。
创建一个新的子进程
process = subprocess.Popen(['ping', '127.0.0.1'], stdout=subprocess.PIPE, stderr=subprocess.PIPE)
stdout, stderr = process.communicate()
print(stdout.decode())
在这个例子中:
- 我们执行了
ping 127.0.0.1命令。 - 使用
subprocess.PIPE来捕获输出。 process.communicate()方法将阻塞,直到进程完成并返回输出。
异步处理
我们也可以启动一个进程而不等待它完成:
process = subprocess.Popen(['sleep', '5'])
print("Process started")
在这个示例中,程序不会阻塞,而是立即返回。
常见参数
- args: 要执行的命令和参数列表。
- stdin, stdout, stderr: 定义子进程的输入、输出和错误流。
- cwd: 设置子进程的当前工作目录。
- shell: 如果为 True,则命令将通过 shell 执行。
设置工作目录
subprocess.run(['ls', '-l'], cwd='/home/user')
上面的命令会在 /home/user 目录下执行 ls -l。
在 shell 中执行命令
subprocess.run('echo $HOME', shell=True)
使用 shell=True 可以直接传入字符串形式的命令。
错误处理
在使用 subprocess 时,可能会遇到各种错误情况,例如命令未找到、权限不足等。可以通过检查异常来处理这些问题。
使用 try-except 捕获异常
try:
subprocess.run(['nonexistent_command'], check=True)
except subprocess.CalledProcessError as e:
print(f'Error: {e}')
在上述代码中,使用 check=True 参数可以确保在命令失败时抛出异常。
注意事项
- 确保命令和参数的正确性,避免因拼写错误引起的问题。
- 使用 shell=True 时要小心,避免命令注入的风险。
- 在处理大型输出时,小心管道缓冲区的大小,适当使用
communicate()。
实用技巧
- 并发执行命令:可以使用
threading或multiprocessing模块与 subprocess 结合。
import threading
def run_command(cmd):
subprocess.run(cmd)
threads = []
for cmd in [['ls', '-l'], ['pwd']]:
t = threading.Thread(target=run_command, args=(cmd,))
threads.append(t)
t.start()
for t in threads:
t.join()
stdout=subprocess.PIPE 和 communicate() 的结合,可以实现实时输出。process = subprocess.Popen(['ping', '127.0.0.1'], stdout=subprocess.PIPE)
for line in iter(process.stdout.readline, b''):
print(line.decode().strip())
总结
subprocess 模块强大且灵活,它能够帮助我们轻松地运行外部命令和管理进程。通过掌握其基本用法及相关参数设置,不仅能够提高 Python 程序的功能性,也能增强用户与系统的交互能力。希望本文对你在使用 subprocess 模块时提供了帮助与启发。



