Python自动化运维快速入门
上QQ阅读APP看书,第一时间看更新

2.4 执行外部命令subprocess

subprocess模块是Python自带的模块,无须再另行安装,它主要用来取代一些旧的模块或方法,如os.system、os.spawn*、os.popen*、commands.*等,因此如果需要使用Python调用外部命令或任务时,则优先使用subprocess模块。使用subprocess模块可以方便地执行操作系统支持的命令,可与其他应用程序结合使用。因此,Python也常被称为胶水语言。

2.4.1 subprocess.run()方法

subprocess.run()是官方推荐使用的方法,几乎所有的工作都可以由它来完成。首先来看一下函数原型:

subprocess.run(args, *, stdin=None, input=None, stdout=None, stderr=None,
shell=False, cwd=None, timeout=None, check=False, encoding=None, errors=None)

该函数返回一个CompletedProcess类(有属性传入参数及返回值)的实例,虽然该函数的参数有很多,但是我们只需要知道几个常用的就可以了。


args代表需要在操作系统中执行的命令,可以是字符串形式(要求shell=True),也可以是列表list类型。

*代表可变参数,一般是列或字典形式。

stdin、stdout、stderr指定了可执行程序的标准输入、标准输出、标准错误文件句柄。

shell代表着程序是否需要在shell上执行,当想使用shell的特性时,设置shell=True,这样就可以使用shell指令的管道、文件名称通配符、环境变量等,不过Python也提供了许多类shell的模块,如glob、fnmatch、os.walk()、os.path.expandvars()、os.path.expanduser()和shutil。

check如果check设置为True,就检查命令的返回值,当返回值为非0时,将抛出CalledProcessError异常。

timeout设置超时时间,如果超时,则强制kill掉子进程。


【示例2-20】下面举例说明。

在Linux系统中如果我们执行一个脚本并获取它的返回值,可有如下两种方法,如图2.12和图2.13所示。

方法一:

图2.12 获取subprocess.run返回值(方法一)

方法二:

图2.13 获取subprocess.run返回值(方法二)

如果要捕获脚本的输出,可以按如图2.14所示的做法。

图2.14 捕获脚本输出

如果传入参数check=True,当returncode不为0时,将会抛出subprocess.CalledProcessError异常;如果传输timeout参数,当运行时间超过timeout时就会抛出TimeoutExpired异常。运行结果如图2.15所示。

图2.15 运行结果

上面的例子虽然很长,但是为了说明超时会抛出TimeoutExpired异常,这在实际工作中非常有用,比如一个任务不确定什么时间完成,可以设置一个超时时间,如果超时仍未完成,可以通过代码控制超时重新运行。如果超时重试3次不成功,就让程序报错退出。

2.4.2 Popen类

先来看一下Popen类的构造函数。

参数的说明可参见表2-5。

表2-5 Popen类构造函数的参数

使用方法如下:

subprocess.Popen(["gedit","abc.txt"])
subprocess.Popen("gedit abc.txt")

这两个方法,后者将不会工作。因为如果是一个字符串的话,就必须是程序的路径才可以。(考虑unix的api函数exec,接受的是字符串列表)。但是下面的可以工作:

subprocess.Popen("gedit abc.txt", shell=True)

这是因为它相当于:

subprocess.Popen(["/bin/sh", "-c", "gedit abc.txt"])

Popen类的对象还有其他实用方法,参见表2-6。

表2-6 Popen类对象的方法

2.4.3 其他方法

(1)subprocess.call(*popenargs, **kwargs):call方法调用Popen()执行程序,并等待它完成。

(2)subprocess. check_call(*popenargs, **kwargs):调用前面的call(),如果返回值非零,则抛出异常。

(3)subprocess. check_output (*popenargs, **kwargs):调用Popen()执行程序,并返回其标准输出。