一. 引言
subprocess
是 Python 标准库中用于创建新进程、连接到它们的输入 / 输出 / 错误管道,并获取它们的返回码的模块。它提供了一种灵活的方式来执行系统命令、运行外部程序,并与它们进行交互。
二. 核心功能
subprocess
模块的主要作用是:
1. 执行外部命令或程序(如系统命令、其他脚本语言程序等)
2. 控制输入 / 输出流(stdin、stdout、stderr)
3. 获取命令执行结果和返回码
4. 管理进程的生命周期
三. 常用方法(功能函数)
1. subprocess.run()
python 3.5+ 引入的高级函数,封装了大部分常用功能,适合大多数场景。基本用法:
import subprocess
# 执行简单命令
result = subprocess.run(["ls", "-l"])
# 查看返回结果
print("返回码:", result.returncode) # 0表示成功,非0表示失败
2. subprocess.Popen
灵活的底层接口,适合需要复杂交互的场景(如实时输出处理、长时间运行的进程等):
import subprocess
# 创建进程对象
proc = subprocess.Popen(["echo", "Hello World"])
# 等待进程结束
proc.wait()
# 获取返回码
print("返回码:", proc.returncode)
重要参数说明:
参数 | 作用 |
---|---|
args | 要执行的命令,可以是字符串或列表 |
shell=True | 是否通过 shell 执行命令(方便使用管道、通配符等,但有安全风险) |
stdout/stderr | 控制输出流,subprocess.PIPE 表示捕获输出,None 表示继承父进程输出 |
stdin | 控制输入流,subprocess.PIPE 表示可以通过管道输入数据 |
text /universal_newlines | 设为 True 时,输入输出为字符串类型,否则为字节类型 |
check=True | 仅用于 run() ,命令返回非 0 状态码时抛出 CalledProcessError 异常 |
cwd | 设置命令执行的工作目录 |
timeout | 超时时间,超过指定时间将终止进程并抛出异常 |
案例:
#!/usr/bin/python
import subprocess
p = subprocess.Popen("uptime && pd",stdout=subprocess.PIPE,stderr=subprocess.PIPE,shell=True)
out,err = p.communicate()
print 'out:---%s' % out
print 'err:---%s' % err
输出:
out:---b' 16:23:32 up 292 days, 42 min, 4 users, load average: 0.01, 0.02, 0.00\n'
err:---b'/bin/sh: pd: command not found\n'
Popen的一些功能:
a). Popen.
poll
():检查子进程是否已经结束。设置并返回returncode属性,没有结束返回None
b). Popen.
wait
(): 等待子进程终止,设置并返回returncode;这个方法可能导致死锁:如果子进程对stdout/stderr使用的管道产生大量输入,可能填满管道的buffer,这样,子进程就会等待其它人读取 这些buffer(可使用communicate避免)。
c). Popen.
communicate
(input=None): 将数据发给子进程的stdin,并从子进程的stdout/stderr读取数据,直到eof。等待子进程结束,返回元组(stdoutdata, stderrdata),注意:读取的数据是存放在内存中的。如果想用这个函数发送数据或者读取数据,创建Popen时需要制定stdin/stdout/stderr为管道(PIPE)
d). Popen.
send_signal
(signal): 向子进程发送指定的信号;
e). Popen.
terminate
(): 终止子进程,在Unix上,就是向子进程发送SIGTERM.
f). Popen.
kill
(): 杀死子进程,在Unix上,就是向子进程发送SIGKILL。
g). Popen.
stdin/
Popen.
stdout/
Popen.
stderr: 创建Popen对象时,参数被设置为PIPE,Popen.stdout将返回一个文件对象用于子进程发送指令。否则返回None.
h).
Popen.
pid : 子进程id
i). Popen.returncode :
子进程的返回值,被poll()和wait()设置(communicate()也会设置)。如果返回值是-N,表示子进程是被Unix的信号N杀死的,进程还没有结束,返回None .
关于异常处理: 在子进程中,如果在加载并执行指定的程序之前,抛出了异常,这个异常会在父进程中被重新抛出。例如,常见的一个异常是OSError(没有找到要执行的程序)。这种异常会多一个字段:child_traceback,该字段包含了从子进程观点来看的traceback信息。如果Popen的参数类型不对,Popen也会抛出ValueError异常。
上面一种方式,会阻塞(等待),直到子进程结束后才会返回,不能及时获得stdout,stderr, 可通过下面方式获得:
#!/usr/bin/python
import subprocess
p = subprocess.Popen("uptime && sleep 10 && pd",stdout=subprocess.PIPE,stderr=subprocess.STDOUT,shell=True)
r = p.poll()
while r is None:
line = p.stdout.readline()
r = p.poll()
line = line.strip()
print line
3. 一些对subprocess.Popen封装的功能:
a). subprocess.call(args, *, stdin=None, stdout=None, stderr=None, shell=False):
父进程等待子进程完成,返回退出信息(returncode,相当于exit code)
b). subprocess.check_call(args, *, stdin=None, stdout=None, stderr=None, shell=False):
父进程等待子进程完成,返回0, 检查退出信息,如果returncode不为0,则举出错误subprocess.CalledProcessError,该对象包含有returncode属 性,可用try...except...来检查.
c). subprocess.
check_output
(args, *, stdin=None, stderr=None, shell=False, universal_newlines=False):
父进程等待子进程完成,返回子进程向标准输出的输出结果.检查退出信息,如果returncode不为0,则举出错误subprocess.CalledProcessError,该对象包含有returncode属性和output属性,output属性为标准输出的输出结果,可用try...except...来检查。
- --------------------------------------------------------------------------------------------------------------------------
深耕运维行业多年,擅长运维体系建设,方案落地。欢迎交流!
“V-x”: ywjw996
《 运维经纬 》