Python中subprocess模块:轻松调用外部程序与命令

张开发
2026/4/9 3:28:10 15 分钟阅读

分享文章

Python中subprocess模块:轻松调用外部程序与命令
01 subprocess模块简介subprocess是Python的标准库它的设计目标是替代旧有的os.system、os.popen等模块提供更统一、更强大的子进程管理功能。使用subprocess可以启动外部程序、获取程序执行结果、管理进程的输入输出和错误信息在自动化脚本、系统管理、程序集成等场景中发挥重要作用。02 核心函数介绍与案例1. subprocess.run()执行命令并等待完成subprocess.run()是subprocess模块中最常用的函数用于执行指定的命令并等待命令执行完毕。它接受args参数命令及其参数以及input等可选参数返回一个CompletedProcess对象包含命令执行结果信息。参数介绍1popenargs指定要执行的命令及参数popenargs是subprocess.run()中最核心的参数必须传入它用于指定要执行的外部命令及其参数。args通常以列表形式传递列表的第一个元素是命令本身后续元素为命令的参数。案例执行简单命令import subprocess # 执行ls命令获取当前目录下的文件列表 result subprocess.run([ls, -l], capture_outputTrue, textTrue) if result.returncode 0: print(命令执行成功输出如下) print(result.stdout) else: print(f命令执行失败错误信息{result.stderr})说明代码中使用subprocess.run()执行ls -l命令capture_outputTrue表示捕获命令的标准输出和标准错误输出textTrue则以文本形式返回输出结果。通过检查returncode判断命令是否执行成功。2stdin、stdout、stderr控制输入输出和错误流stdin指定子进程的标准输入可以是文件对象、字节串或字符串当textTrue时。如果不指定子进程的标准输入将继承父进程的标准输入。stdout指定子进程的标准输出常见取值为subprocess.PIPE用于捕获输出、文件对象或None默认继承父进程的标准输出。stderr指定子进程的标准错误输出取值和用法与stdout类似。案例捕获命令的输出和错误信息import subprocess # 执行一个错误的命令捕获输出和错误 result subprocess.run([ls, nonexistent_file], stdoutsubprocess.PIPE, stderrsubprocess.PIPE, textTrue) print(标准输出, result.stdout) print(标准错误, result.stderr) #输出为 标准输出 标准错误 ls: nonexistent_file: No such file or directory3capture_output快速捕获输出和错误capture_output是一个布尔值参数当设置为True时相当于同时将stdout和stderr设置为subprocess.PIPE并自动捕获子进程的标准输出和标准错误。案例使用capture_output简化代码import subprocess # 执行一个错误的命令捕获输出和错误 result subprocess.run([ls, nonexistent_file],capture_outputTrue, textTrue) print(标准输出, result.stdout) print(标准错误, result.stderr)4shell使用系统shell执行命令shell是一个布尔值参数默认为False。当shellTrue时命令会通过系统的shell如bash执行此时执行命令可以是字符串形式如下“ls nonexistent_file”。import subprocess # 执行一个错误的命令捕获输出和错误 result subprocess.run(ls nonexistent_file,shellTrue,capture_outputTrue, textTrue) print(标准输出, result.stdout) print(标准错误, result.stderr)但这种方式可能会引入安全问题例如import subprocess user_input ; rm -rf /# 恶意输入示例 # 危险操作可能会删除系统根目录 subprocess.run(fecho {user_input}, shellTrue)因此除非必要否则不建议使用shellTrue若确实需要可以考虑使用shlex.quote对输入进行转义。5cwd指定子进程的工作目录cwd参数用于指定子进程执行时的工作目录。如果不指定子进程将在父进程的当前工作目录下执行。案例在指定目录下执行命令import subprocess # 在/tmp目录下执行ls命令 result subprocess.run([ls], cwd/tmp, capture_outputTrue, textTrue) print(result.stdout)6timeout设置命令执行的超时时间timeout参数用于设置子进程执行的最长时间单位为秒。如果子进程在指定时间内未执行完毕将引发subprocess.TimeoutExpired异常。案例设置命令执行超时import subprocess try: # 执行ping命令设置超时时间为5秒 result subprocess.run([ping, www.baidu.com], timeout5, capture_outputTrue, textTrue) print(result.stdout) except subprocess.TimeoutExpired: print(命令执行超时)7check检查命令执行状态check是一个布尔值参数默认为False。当checkTrue时如果子进程的返回码不为0将引发subprocess.CalledProcessError异常。案例检查命令是否执行成功import subprocess try: # 执行一个可能失败的命令开启check检查 result subprocess.run([ls,nonexistent_file], checkTrue, capture_outputTrue, textTrue) except subprocess.CalledProcessError: print(命令执行失败)2. subprocess.Popen()创建并管理子进程subprocess.Popen()函数用于创建一个新的子进程并返回一个Popen对象通过该对象可以控制子进程的执行、获取输出、与子进程进行交互。subprocess.Popen()是subprocess模块的底层接口与run()的主要区别在于阻塞 vs 非阻塞run()是阻塞式的等待命令执行完毕而Popen()是非阻塞式的立即返回进程对象。灵活性Popen()提供更底层的控制适合需要实时交互或复杂进程管理的场景。参数介绍1args命令及参数与run()相同指定要执行的命令。推荐使用列表形式避免安全风险。import subprocess # 正确写法列表形式 p subprocess.Popen([ls, -l], stdoutsubprocess.PIPE) # 危险写法shellTrue # p subprocess.Popen(ls -l, shellTrue)2stdin/stdout/stderr控制输入输出与run()类似但更灵活支持实时处理流数据。常见取值subprocess.PIPE创建管道用于捕获输出或提供输入。文件对象将输出 / 输入重定向到文件。None默认继承父进程。案例实时获取命令输出import subprocess # 执行命令并实时获取输出 p subprocess.Popen([ping, www.baidu.com], stdoutsubprocess.PIPE, textTrue) # 逐行读取输出 for line in iter(p.stdout.readline, ): print(line.strip()) p.wait() # 等待进程结束3shell通过shell执行命令慎用与run()的shell参数功能相同但风险更高。仅在必要时使用并确保输入经过严格过滤。# 安全风险示例切勿在生产环境使用 user_input example.txt; rm -rf / subprocess.Popen(fcat {user_input}, shellTrue)4cwd指定工作目录与run()的cwd参数功能相同。import subprocess # 在/tmp目录下执行命令 p subprocess.Popen([ls], cwd/tmp, stdoutsubprocess.PIPE) print(p.stdout.read().decode())5env自定义环境变量覆盖或添加子进程的环境变量。有些命令执行时需要获取环境变量信息否则执行shell命令可能会报错import subprocess import os # 自定义环境变量 my_env {**os.environ, MY_VAR: custom_value} p subprocess.Popen([printenv, MY_VAR], envmy_env, stdoutsubprocess.PIPE) print(p.stdout.read().decode()) # 输出: custom_value6bufsize控制缓冲区大小-1默认使用系统默认缓冲区大小。0无缓冲仅适用于stdin、stdout、stderr为管道时。1行缓冲仅在textTrue时有效。1指定缓冲区大小字节。# 无缓冲模式实时获取输出 p subprocess.Popen([ls], stdoutsubprocess.PIPE, bufsize0)7start_new_sessionWindows/Linux在新会话中启动进程。# 在Windows或Linux上创建新会话 p subprocess.Popen([python, script.py], start_new_sessionTrue)一些应用场景1. 实时监控命令输出import subprocess # 实时监控日志文件 p subprocess.Popen([tail, -f, /var/log/syslog], stdoutsubprocess.PIPE, textTrue) try: for line in iter(p.stdout.readline, ): print(f日志: {line.strip()}) except KeyboardInterrupt: p.terminate() # 按CtrlC终止监控2. 并行执行多个命令import subprocess import time # 并行执行多个命令 commands [ [sleep, 2], [ls, -l], [echo, Hello] ] processes [subprocess.Popen(cmd) for cmd in commands] # 等待所有进程结束 for p in processes: p.wait() print(所有命令执行完毕)3. 复杂交互场景如FTP客户端import subprocess # 启动交互式FTP客户端 p subprocess.Popen([ftp, ftp.example.com], stdinsubprocess.PIPE, stdoutsubprocess.PIPE, stderrsubprocess.PIPE,textTrue) # 发送登录命令 p.stdin.write(user\n) p.stdin.write(password\n) p.stdin.flush() # 读取响应 output p.stdout.read(1024)Popen对象的其他方法方法描述p.wait(timeout)等待进程结束并返回返回码可设置超时超时抛出TimeoutExpired。p.communicate(inputNone, timeoutNone)与进程交互发送输入、获取输出等待进程结束。p.send_signal(signal)向进程发送信号如signal.SIGTERM。p.terminate()终止进程发送 SIGTERM 信号。p.kill()强制杀死进程发送 SIGKILL 信号。p.poll()检查进程是否结束返回返回码未结束返回None。3. subprocess.check_output()执行命令并返回输出subprocess.check_output()函数执行指定命令若命令执行成功返回命令的标准输出若执行失败返回码非 0则抛出CalledProcessError异常。案例获取系统磁盘空间信息import subprocess try: result subprocess.check_output([df, -h], textTrue) print(磁盘空间信息) print(result) except subprocess.CalledProcessError as e: print(f命令执行失败错误码{e.returncode}错误信息{e.output})说明代码执行df -h命令获取磁盘空间信息若命令执行失败捕获异常并输出错误信息。subprocess模块赋予了Python与外部世界交互的强大能力通过掌握这些核心函数我们可以在 Python开发中实现更丰富的功能无论是自动化运维、数据采集还是程序集成subprocess都能成为你的得力助手。如果在使用过程中有任何疑问或新发现欢迎在评论区分享交流

更多文章