商城首页欢迎来到中国正版软件门户

您的位置: 首页 > 文章列表 > 编程开发 > Python使用subprocess模块轻松调用外部程序与命令

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

  发布于2026-07-13 阅读(0)

扫一扫,手机访问

01 subprocess模块简介

subprocess是Python标准库里的一个模块,它要来取代之前那些零散的os.system、os.popen之类的工具,提供一套更统一、也更强大的子进程管理方案。简单来说,通过它我们可以启动外部程序、拿到程序的执行结果、甚至还能控制进程的输入、输出以及错误信息。这在自动化脚本编写、系统管理、程序集成这些场景里,基本上是绕不开的角色。

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

02 核心函数介绍与案例

1. subprocess.run():执行命令并等待完成

要说subprocess里最常用的函数,那非run()莫属。它负责执行你指定的命令,然后乖乖地等命令跑完,才会把控制权交回来。它接受一个args参数来定义要执行的命令,还有一些像input这样的可选参数,返回的是一个CompletedProcess对,里面包含了这次执行的结果信息。

参数介绍:

1)popenargs:指定要执行的命令及参数

这个popenargs可以说是run()里最核心的参数了,必须得传。它用来指定要执行的外部命令以及相关的参数。通常建议以列表的形式传递,列表的第一个元素是命令本身,后面的则是各个参数。

案例:执行简单命令

import subprocess
# 执行ls命令,获取当前目录下的文件列表
result = subprocess.run(['ls', '-l'], capture_output=True, text=True)
if result.returncode == 0:
    print("命令执行成功,输出如下:")
    print(result.stdout)
else:
    print(f"命令执行失败,错误信息:{result.stderr}")

说明:这段代码用subprocess.run()执行了ls -l命令。capture_output=True意味着捕获命令的标准输出和标准错误,text=True则是让输出以文本形式返回。最后通过检查returncode来判断命令到底成没成功。

2)stdin、stdout、stderr:控制输入输出和错误流

  • stdin:用来指定子进程的标准输入,可以是一个文件对象、字节串,或者当text=True时也可以是字符串。如果不指定,子进程会直接继承父进程的标准输入。
  • stdout:指定子进程的标准输出。常见的取值有subprocess.PIPE(用于捕获输出)、文件对象,或者None(默认继承父进程的标准输出)。
  • stderr:指定子进程的标准错误输出,用法和stdout类似。

案例:捕获命令的输出和错误信息

import subprocess
# 执行一个错误的命令,捕获输出和错误
result = subprocess.run(['ls', 'nonexistent_file'], stdout=subprocess.PIPE, stderr=subprocess.PIPE, text=True)
print("标准输出:", result.stdout)
print("标准错误:", result.stderr)
#输出为:
标准输出: 
标准错误: ls: nonexistent_file: No such file or directory

3)capture_output:快速捕获输出和错误

这是一个布尔值参数。当设为True时,它相当于同时把stdout和stderr都设成了subprocess.PIPE,也就是自动帮你捕获子进程的标准输出和标准错误,省得你写两行代码。

案例:使用capture_output简化代码

import subprocess
# 执行一个错误的命令,捕获输出和错误
result = subprocess.run(['ls', 'nonexistent_file'],capture_output=True, text=True)
print("标准输出:", result.stdout)
print("标准错误:", result.stderr)

4)shell:使用系统shell执行命令

shell同样是一个布尔值参数,默认为False。当它设为True时,命令会通过系统的shell(比如bash)来执行,此时你可以把命令写成字符串形式,像下面这样ls nonexistent_file。

import subprocess
# 执行一个错误的命令,捕获输出和错误
result = subprocess.run('ls nonexistent_file',shell=True,capture_output=True, text=True)
print("标准输出:", result.stdout)
print("标准错误:", result.stderr)

但得留个心眼,这种方式可能会带来安全问题,比如:

import subprocess
user_input = "; rm -rf /"# 恶意输入示例
# 危险操作!可能会删除系统根目录
subprocess.run(f'echo {user_input}', shell=True)

所以,除非真的有必要,否则不建议用shell=True。如果实在要用,可以考虑用shlex.quote对输入做一下转义处理。

5)cwd:指定子进程的工作目录

cwd参数用来指定子进程执行时的工作目录。如果不指定,子进程就会在父进程当前的目录下执行。

案例:在指定目录下执行命令

import subprocess
# 在/tmp目录下执行ls命令
result = subprocess.run(['ls'], cwd='/tmp', capture_output=True, text=True)
print(result.stdout)

6)timeout:设置命令执行的超时时间

timeout参数,顾名思义,就是设置子进程执行的最长时间,单位是秒。如果子进程在规定时间内没跑完,就会抛出一个subprocess.TimeoutExpired异常。

案例:设置命令执行超时

import subprocess
try:
# 执行ping命令,设置超时时间为5秒
    result = subprocess.run(['ping', 'www.baidu.com'], timeout=5, capture_output=True, text=True)
    print(result.stdout)
except subprocess.TimeoutExpired:
    print("命令执行超时!")

7)check:检查命令执行状态

check也是布尔值,默认是False。当设为True时,如果子进程的返回码不是0,就会抛出subprocess.CalledProcessError异常。

案例:检查命令是否执行成功

import subprocess
try:
# 执行一个可能失败的命令,开启check检查
 result = subprocess.run(['ls','nonexistent_file'], check=True, capture_output=True, text=True)
except subprocess.CalledProcessError:
 print("命令执行失败!")

2. subprocess.Popen():创建并管理子进程

subprocess.Popen()用于创建一个新的子进程,并返回一个Popen对象。通过这个对象,你可以控制子进程的执行、获取输出、甚至和它进行实时交互

它是subprocess模块的底层接口,和run()相比,有几个关键区别:

  • 阻塞 vs 非阻塞:run()是阻塞式的,必须等命令执行完才返回;而Popen()是非阻塞式的,它立即返回一个进程对象,你可以后续再操作。
  • 灵活性:Popen()提供了更底层的控制,适合那些需要实时交互或者更复杂进程管理的场景。

参数介绍:

1)args:命令及参数

和run()一样,指定要执行的命令。推荐用列表形式,能避免一些安全风险。

import subprocess
# 正确写法:列表形式
p = subprocess.Popen(['ls', '-l'], stdout=subprocess.PIPE)
# 危险写法(shell=True):
# p = subprocess.Popen('ls -l', shell=True)

2)stdin/stdout/stderr:控制输入输出

用法和run()类似,但更灵活,支持实时处理流数据。

常见取值

  • subprocess.PIPE:创建管道,用于捕获输出或提供输入。
  • 文件对象:将输出或输入重定向到文件。
  • None(默认):继承父进程。

案例:实时获取命令输出

import subprocess
# 执行命令并实时获取输出
p = subprocess.Popen(['ping', 'www.baidu.com'], stdout=subprocess.PIPE, text=True)
# 逐行读取输出
for line in iter(p.stdout.readline, ''):
    print(line.strip())
p.wait()  # 等待进程结束

3)shell:通过shell执行命令(慎用)

和run()的shell参数功能一样,但风险更高。只在必要的时候用,而且务必确保输入经过严格的过滤。

# 安全风险示例(切勿在生产环境使用)
user_input = "example.txt; rm -rf /"
subprocess.Popen(f'cat {user_input}', shell=True)

4)cwd:指定工作目录

和run()的cwd参数一样。

import subprocess
# 在/tmp目录下执行命令
p = subprocess.Popen(['ls'], cwd='/tmp', stdout=subprocess.PIPE)
print(p.stdout.read().decode())

5)env:自定义环境变量

可以用来覆盖或添加子进程的环境变量。(有些命令执行时需要获取环境变量,否则执行shell命令可能会报错)

import subprocess
import os
# 自定义环境变量
my_env = {**os.environ, 'MY_VAR': 'custom_value'}
p = subprocess.Popen(['printenv', 'MY_VAR'], env=my_env, stdout=subprocess.PIPE)
print(p.stdout.read().decode())  # 输出: custom_value

6)bufsize:控制缓冲区大小

  • -1(默认):使用系统默认缓冲区大小。
  • 0:无缓冲(仅适用于stdin、stdout、stderr为管道时)。
  • 1:行缓冲(仅在text=True时有效)。
  • >1:指定缓冲区大小(字节)。
# 无缓冲模式,实时获取输出
p = subprocess.Popen(['ls'], stdout=subprocess.PIPE, bufsize=0)

7)start_new_session(Windows/Linux)

在新会话中启动进程。

# 在Windows或Linux上创建新会话
p = subprocess.Popen(['python', 'script.py'], start_new_session=True)

一些应用场景

1). 实时监控命令输出

import subprocess
# 实时监控日志文件
p = subprocess.Popen(['tail', '-f', '/var/log/syslog'], stdout=subprocess.PIPE, text=True)
try:
    for line in iter(p.stdout.readline, ''):
        print(f"日志: {line.strip()}")
except KeyboardInterrupt:
    p.terminate()  # 按Ctrl+C终止监控

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'], 
stdin=subprocess.PIPE, 
stdout=subprocess.PIPE,
stderr=subprocess.PIPE,text=True)
# 发送登录命令
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(input=None, timeout=None)

与进程交互(发送输入、获取输出),等待进程结束。

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'], text=True)
    print("磁盘空间信息:")
    print(result)
except subprocess.CalledProcessError as e:
    print(f"命令执行失败,错误码:{e.returncode},错误信息:{e.output}")

说明:这段代码执行df -h命令来获取磁盘空间信息。如果命令跑崩了,就捕获异常并输出错误信息。

可以说,subprocess模块赋予了Python跟外部世界打交道的能力。把这些核心函数吃透了,不管是自动化运维、数据采集,还是程序集成,都能派上大用场。

本文转载于:https://www.jb51.net/python/362738jai.htm 如有侵犯,请联系zhengruancom@outlook.com删除。
免责声明:正软商城发布此文仅为传递信息,不代表正软商城认同其观点或证实其描述。

热门关注