一、背景
Python 中的模块subprocess
允许您创建新进程、连接到其输入/输出/错误管道并获取其返回代码。它是一个功能强大的模块,可用于在 Python 代码中运行和管理子进程。
应用场景:
-
调用操作系统的命令,或者与其他进程进行交互
-
处理系统任务,执行外部程序,捕获命令输出,甚至进行错误处理和超时控制
-
本人博客 如何用python 执行一些linux 命令同时得到返回值的三种方法
subprocess.run() 适用于简单的命令执行 subprocess.call() 用于执行命令并返回退出码 subprocess.Popen() 适合需要更精细控制的高级用法
二、主要功能
2.1 subprocess.run()
启用一个进程并等待其完成,执行指定的命令,并返回执行的结果。
- 运行简单的命令 使用
subprocess.run()
capture_output=True
捕捉命令输出结果stdout
和错误stderr
text=True
输出结果以字符串形式返回,不是字节流import subprocess result = subprocess.run(['ls', '-l'], capture_output=True, text=True) print(output.returncode) # 0 成功 print("stdout:", result.stdout) # 输出结果 print("stderr:", result.stderr) # 输出错误信息
returncode
通过检查结果的属性来检查命令是否成功;
check=True
来启用错误检查import subprocess try: result = subprocess.run(['ls', '-l', '/nonexistent'], capture_output=True, text=True, check=True) except subprocess.CalledProcessError as e: print("Command failed with return code", e.returncode) print("stderr:", e.stderr)
- 运行 Shell 命令:可以使用
shell=True
。请谨慎使用此选项,因为它可能导致 shell 注入等安全风险import subprocess result = subprocess.run('echo $HOME', shell=True, capture_output=True, text=True) print("stdout:", result.stdout)
- 设置超时
import subprocess try: # 设置命令超时时间为5秒 result = subprocess.run(["sleep", "10"], capture_output=True, text=True, timeout=5) except subprocess.TimeoutExpired as e: print(f"Command timed out: {e}")
2.2 subprocess.Popen
如果你需要更复杂的控制,比如与进程进行实时通信或处理输入输出流,Popen()
方法是最强大的选择。
通过它,你可以精确地控制子进程的启动和管理
Popen()
返回一个进程对象,你可以通过它进行更多控制,例如获取输出、错误信息,或者向子进程发送输入
-
import subprocess process = subprocess.Popen(['ping', 'google.com'], stdout=subprocess.PIPE, stderr=subprocess.PIPE) stdout, stderr = process.communicate() print('输出:', stdout.decode()) print('错误:', stderr.decode())
-
import subprocess # 启动一个子进程并与它交互 process = subprocess.Popen(['ls', '-l'], stdout=subprocess.PIPE, stderr=subprocess.PIPE, text=True) # 读取输出和错误 stdout, stderr = process.communicate() print("stdout:", stdout) print("stderr:", stderr)
2.3 subprocess.call
call()
方法会执行命令,但不会返回进程的详细信息。
如果你仅仅需要执行一个命令并检查它是否成功,call()
就非常合适。
return_code
会返回命令执行的退出码。如果命令成功执行,通常返回0
-
import subprocess # 执行一个系统命令并返回状态码 return_code = subprocess.call(['ls', '-l']) print('命令执行完成,状态码:', return_code) 这里,return_code会返回命令执行的退出码。如果命令成功执行,通常返回0。
三、高级用法
-
3.1
运行带有管道的命令
如果你需要执行多个命令,并希望将它们的输出通过管道连接起来,subprocess也能轻松处理。以下是一个例子,先列出当前目录的文件,再将结果通过grep命令过滤:
在这个示例中,p1命令列出了文件,而p2则通过管道过滤出了所有的.py文件。import subprocess # 第一个命令 p1 = subprocess.Popen(['ls', '-l'], stdout=subprocess.PIPE) # 第二个命令,通过管道传输数据 p2 = subprocess.Popen(['grep', '.py'], stdin=p1.stdout, stdout=subprocess.PIPE) # 获取最终输出 output = p2.communicate()[0] print('Python文件列表:') print(output.decode())
-
与子进程交互:提供输入和获取输出
import subprocess process = subprocess.Popen(['grep', 'hello'], stdin=subprocess.PIPE, stdout=subprocess.PIPE, text=True) stdout, stderr = process.communicate(input='hello world\n') print("stdout:", stdout)
使用subprocess.Popen启动一个子进程,执行grep命令 stdin=subprocess.PIPE表示我们可以向子进程提交输入数据 stdout=subprocess.PIPE表示我们可以从子进程接收数据输出 使用process.communicate()方法提交输入并获取输出
subprocess 可以处理进程间的标准输入输出流,允许你向外部进程发送数据,并获取其输出。这对于需要与子进程进行交互的情况非常有用
在这个例子中,我们通过input='Hello from Python!'
将输入传递给子进程,并从子进程获取输出result = subprocess.run( ['python3', '-c', 'import sys; print(sys.stdin.read())'], input='Hello from Python!', capture_output=True, text=True ) print(result.stdout) # 输出 "Hello from Python!"
-
subprocess还能做实时输出流处理:
process = subprocess.Popen(['ping', 'python.org'], stdout=subprocess.PIPE, universal_newlines=True) while True: output = process.stdout.readline() if output == '' and process.poll() is not None: break if output: print(output.strip())
-
如果你需要更细粒度的控制,创建一个进程并实时获取输出
from subprocess import Popen, PIPE # 创建一个进程并实时获取输出 with Popen(['ping', 'google.com'], stdout=PIPE, text=True) as proc: while True: line = proc.stdout.readline() if not line: break print(line, end='')
-
备份数据库
subprocess.run(['mysqldump', '-u', 'root', '-p', 'mydb', '>', 'backup.sql'], shell=True)
-
subprocess 可以用于系统监控,检查系统状态或资源使用情况
# 检查CPU使用率 result = subprocess.run(['top', '-bn1'], capture_output=True, text=True) print(result.stdout)