注册 登录
  • 欢迎访问"运维那点事",推荐使用Google浏览器访问,可以扫码关注本站的"微信公众号"。
  • 如果您觉得本站对你有帮助,那么可以扫码捐助以帮助本站更好地发展。

Python模块:subprocess

Python模块 彭东稳 292次浏览 已收录 0个评论

一、subprocess

在早期的Python版本中,我们主要是通过os.system()、os.popen()、os.spawn()等函数来执行命令行指令的,另外还有一个很少使用的commands模块。从Python 2.4开始,Python引入subprocess模块来管理子进程,以取代一些旧模块的方法。subprocess不但可以调用外部的命令作为子进程,而且可以连接到子进程的input/output/error管道,获取相关的返回信息。

运行Python的时候,我们都是在创建并运行一个进程。像Linux进程那样,一个进程可以fork一个子进程,并让这个子进程exec另外一个程序。在Python中,我们通过标准库中的subprocess包来fork一个子进程,并运行一个外部的程序。

subprocess包中定义有数个创建子进程的函数,这些函数分别以不同的方式创建子进程,所以我们可以根据需要来从中选取一个使用。另外subprocess还提供了一些管理标准流(standard stream)和管道(pipe)的工具,从而在进程间使用文本通信。

二、subprocess.run()

先来看看subprocess.run()方法,这也是使用较多的方法。在Python 3.5之后的版本中,官方文档中提倡通过subprocess.run()方法替代其他函数来使用subproccess模块的功能。标准使用方式如下:

subprocess.run()返回了一个res类,其中包含了命令运行参数,运行返回状态码和输出内容。如下格式:

所以我们可以很轻松可以获取到相关属性信息,如:res.returncode获取状态码,res.stdout获取标准输出信息等。

注意:如果加上了check=True参数,表示命令执行失败会抛出异常。

  • 关于输出

我们可以看到,上面输出的结果是 b’xxxxx’,这是一个bytes类型的数据。实际使用中需要将其转换为字符串格式。

既然转换成字符串了,那么自然就可以使用字符串相关的方法了。

  • 关于shell参数

shell默认为False。在Linux下,shell=False时,如果args是字符串,那么只能是命令,不能包含任何参数,否则报错;如果args是一个列表list,则args的第一项是定义程序命令字符串,其它项是调用系统Shell时的附加参数。

shell=True时,如果args是字符串,Popen()直接调用系统的Shell来执行,字符串格式和shell终端书写格式一样;如果args是一个列表list,则args的第一项是定义程序命令字符串,其它项是调用系统Shell时的附加参数。官方推荐shell=True时,使用字符串方式传递参数。

如果想使用shell中的管道,重定向,文件通配符,环境变量等功能,例如”ifconfig | grep eth0 > mm”,那么只能使用shell=True,并且使用字符串来传递。

综上,shell=True功能最强大的,但因为强大也存在安全风险,需要谨慎的对待传递的参数。

  • 关于超时

很多脚本运行时会卡住,导致调用脚本一直等待,这很显然不是我们想看到的,因此执行命令的超时Timeout设置很有必要。好在subprocess.run()提供了timeout参数,比如上面我们设置timeout=30,表示如果在30秒内无法执行完毕,会爆出异常。

我们也可以使用try、except捕捉这个异常:

三、subprocess.Popen()

实际上,上面的几个函数都是基于Popen()的封装(wrapper)。这些封装的目的在于让我们容易使用子进程。当我们想要更个性化我们的需求的时候,就要转向Popen类,该类生成的对象用来代表子进程。与上面的封装不同,Popen对象创建后,主程序不会自动等待子进程完成。我们必须调用对象的wait()方法,父进程才会等待(也就是阻塞block),举例:

然后重定向标准输出:

重定向错误输出:

可修改输出方式,比如控制台、文件等。

四、子进程的文本流控制

子进程的标准输入、标准输出和标准错误如下属性分别表示:stdin、stdout、stderr。

可以在Popen()建立子进程的时候改变标准输入、标准输出和标准错误,并可以利用subprocess.PIPE将多个子进程的输入和输出连接在一起,构成管道(pipe),如下例子:

subprocess.PIPE实际上为文本流提供一个缓存区。child1的stdout将文本输出到缓存区,随后child2的stdin从该PIPE中将文本读取走。child2的输出文本也被存放在PIPE中,直到communicate()方法从PIPE中读取出PIPE中的文本。

注意:communicate()是Popen对象的一个方法,该方法会阻塞父进程,直到子进程完成。

<参考>

https://www.jianshu.com/p/8e582146bd4c

https://mp.weixin.qq.com/s/JdUElbYNDbut6sDbXmiSWw


如果您觉得本站对你有帮助,那么可以支付宝扫码捐助以帮助本站更好地发展,在此谢过。
喜欢 (1)or分享 (0)
关于作者:

您必须 登录 才能发表评论!