一. 引言

   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=Nonestdout=Nonestderr=Noneshell=False):

   父进程等待子进程完成,返回退出信息(returncode,相当于exit code)

b).   subprocess.check_call(args*stdin=Nonestdout=Nonestderr=Noneshell=False):

   父进程等待子进程完成返回0, 检查退出信息,如果returncode不为0,则举出错误subprocess.CalledProcessError,该对象包含有returncode属 性,可用try...except...来检查.

c). subprocess.check_output(args*stdin=Nonestderr=Noneshell=Falseuniversal_newlines=False):

     父进程等待子进程完成,返回子进程向标准输出的输出结果.检查退出信息,如果returncode不为0,则举出错误subprocess.CalledProcessError,该对象包含有returncode属性和output属性,output属性为标准输出的输出结果,可用try...except...来检查。

-  --------------------------------------------------------------------------------------------------------------------------

                         深耕运维行业多年,擅长运维体系建设,方案落地。欢迎交流!

                                                     “V-x”: ywjw996

                                                     《 运维经纬 》


 

更多推荐