Python中使用subprocess库创建附加进程
作者:李元静 发布时间:2022-01-01 06:30:25
前言
subprocess库提供了一个API创建子进程并与之通信。这对于运行生产或消费文本的程序尤其有好处,因为这个API支持通过新进行的标准输入和输出通道来回传数据。
本篇,将详细介绍Python创建附加进行的库:subprocess。
run(运行外部命令)
subprocess库本身可以替换os.system(),os.spawnv()等函数。现在我们来通过subprocess库运行一个外部命令,但不采用os.system()。示例如下:
import subprocess
completed = subprocess.run('whoami')
print(completed.returncode)
这里我们运行了一个windows系统常用的whoami命令,返回当前用户的名称,输出如下:
这里,我们使用了subprocess.run调用了子进程运行windows命令。它返回一个CompletedProcess实例,它包含了与进行有关的信息。returncode为子进程的退出状态码。通常情况下,退出状态码为0则表示进程成功运行了;一个负值-N表示这个子进程被信号N终止了。
该函数还有许多参数,比如shell,默认值为False表示直接运行命令,如果主动赋值为True则会创建一个中间shell进程,由这个进程运行命令。
import subprocess
completed = subprocess.run('echo 123',shell=True)
print(completed.returncode)
比如这里,我们打印123。
该库还有一个call()函数,subprocess.run有一个check参数,如果没有设置该参数,等价于调用了call()函数。check默认值为False。
对于run()函数启动的进程,它的标准输入输出通道会绑定到父进程的输入输出。这说明调用程序无法捕获命令的输出。不过,我们可以通过为stdout和stderr参数传入PIPE来捕获输出,以备以后处理。
import subprocess
completed = subprocess.run('whoami',stdout=subprocess.PIPE)
print(completed.returncode)
print(len(completed.stdout))
print(completed.stdout.decode('UTF-8'))
运行之后,效果如下:
如果设置run()函数的参数check=True与stdout为PIPE,等价于调用了check_output()函数。
通过Shell返回消息
本例会通过一个子shell运行命令,在命令返回错误码并退出之前,将详细输入到控制台。实例如下:
import subprocess
try:
completed = subprocess.run(
'echoa 123',
shell=True,
stdout=subprocess.PIPE,
stderr=subprocess.PIPE, )
except subprocess.CalledProcessError as err:
print("ERROR:", err)
else:
print("else")
print(completed.returncode)
print(len(completed.stdout))
print(completed.stdout.decode('UTF-8'))
print(len(completed.stderr))
print(completed.stderr.decode('gbk'))
运行之后,效果如下:
这里我们输入了一个错误的命令,可以看到因为命令错误,并没有输出命令的执行结果,0和64中间就是completed.stdout,为空。而命令将错误消息返回了。这是因为我们设置了stdout与stderr为subprocess.PIPE,表明这些通道要开放。这样我们才能获取子shell运行的结果获取所运行的错误提示。(读者可以将命令改正确后可以发现错误消息没有了,正确执行结果会输出。这就是subprocess库创建进程的通信机制)
需要注意的是,如果需要抑制输出效果,可以将stdout与stderr设置为subprocess.DEVNULL。不过改了之后,上面代码肯定会报错,因为管道关闭,通信也就关闭了。也就是没有这些参数了。
直接处理管道
subprocess库还有一个非常重要的类Popen,它是用来建立其他API的底层API,对更复杂的进程交互很有用。
比如run(),call(),check_call()和check_output()函数都是Popen类的包装器。直接使用Popen可以更好的控制如何运行命令以及如何处理输入和输出流。Popen的构造函数利用参数建立新进程,使父进程可以通过管道与之通信。
下面,我们来分别介绍进程间通信的方式。
与进程的单项通信
要运行一个进程并读取它的所有输出,可以设置stdout为PIPE并调用communicate()函数。示例如下:
import subprocess
prc = subprocess.Popen('whoami', stdout=subprocess.PIPE)
stdout_value = prc.communicate()[0].decode('utf-8')
print(repr(stdout_value))
如上面代码所示,Popen会在内部管理数据读取。运行之后,效果如下:
如果你需要调用一个管道,并完成写数据的操作,可以设置stdin为PIPE。
import subprocess
prc = subprocess.Popen(["cmd", "/c", 'type', '-'], stdin=subprocess.PIPE)
prc.communicate('stdin'.encode('UTF-8'))
与进程的双向通信
要完成进程的双向通信,可以直接将stdin与stdout都设置为PIPE即可。示例如下:
import subprocess
cmd = "cmd /c type E:/Project/debug.log"
cmd.encode('utf-8')
prc = subprocess.Popen(cmd, stdin=subprocess.PIPE, stdout=subprocess.PIPE)
msg = 'stdin'.encode('UTF-8')
stdout_value = prc.communicate(msg)[0].decode('utf-8')
print(repr(stdout_value))
至于如果命令行错误需要捕获错误消息,可以直接将stderr也设置为PIPE。
连接管道段
在Linux系统中,我们可以将多个命令连接成一个管线,即可以把它们的输入输出串联在一起。通过Popen我们也可以完成类似的操作,只需要将一个Popen实例的stdout属性被用左管线中下一个Popen实例的stdin参数即可。至于最后肯定还是要设置为PIPE,毕竟我们还是要获取多个管道段消息结果,示例如下:
import subprocess
cmd1 = "cmd /c type E:/Project/debug.log"
proc1 = subprocess.Popen(cmd1, stdout=subprocess.PIPE, encoding='utf-8')
cmd2 = "tree /F | findstr 拒绝访问"
proc2 = subprocess.Popen(cmd1, stdout=subprocess.PIPE, stdin=proc1.stdout, encoding='utf-8')
result = proc2.stdout
for line in result:
print(line.decode('utf-8').strip())
sys的命令交互
在我们学习Python时,一般使用input()进行用户输入数据。但是其实sys库也可以进行输入输出判断,但它涉及的是进程间的交互,示例如下:
import sys
sys.stderr.write('开始\n')
sys.stderr.flush()
while True:
next_line = sys.stdin.readline()
sys.stderr.flush()
if next_line.strip() == "9599":
break
sys.stdout.write(next_line)
sys.stdout.flush()
sys.stderr.write('结束\n')
sys.stderr.flush()
运行之后,效果如下:
来源:https://blog.csdn.net/liyuanjinglyj/article/details/116460635


猜你喜欢
- 本文实例为大家分享了js左右轮播图的具体代码,供大家参考,具体内容如下html代码<!DOCTYPE html><html
- 本文实例讲述了JS简单实现无缝滚动效果。分享给大家供大家参考,具体如下:<!doctype html><title>
- 引言:Python中的变量在使用中很流畅,可以不关注类型,任意赋值,对于开发来说效率得到了提升,但若不了解其中的机理,往往也会犯一些小错,让
- 如何导入数据数据可能有各种格式,虽然常见的是HDFS,但是因为在Python爬虫中数据库用的比较多的是MongoDB,所以这里会重点说说如何
- 当然,如果你的网站文章中有图片,那么请记得一定要打上自己的LOGO,而且这个LOGO不要固定在这些图片的某个角落里,一定要随机出现在图片的任
- Chrome的CSS支持程度 :Green / √ means current support.Orange / Δ means that
- 下面先看下python 使用值排序字典的方法In [8]: a={'x':11,'y':22,'c&
- 环境: 开发的IDE:JBuilderX 使用的数据库:MS Sql Server 2000 使用的数据库驱动:JSQL Driver(JD
- Timedelta转换为Int或Float方式Pandas处理import pandas as pddataSet['t']
- 目前可实现:MD5算法、SHA256算法、先MD5后SHA256、先SHA256后MD5、两次MD5、两次SHA256、前8位MD5算法后8
- 简介本文主要简述如何通过sklearn模块来进行预测和学习,最后再以图表这种更加直观的方式展现出来数据集学习数据预测数据数据处理数据分离因为
- mysql 获取规定时间段内的统计数据按年统计SELECT count(*), DATE_FORMAT(orde
- 本文,我们将回到之前写的showMovieHandler方法,并更新它以返回一个JSON响应,表示系统中的单个电影信息。类似于:{? ? &
- 本文实例讲述了Python简单实现安全开关文件的两种方式。分享给大家供大家参考,具体如下:以下代码经Python3.3测试。方式1:try:
- golang中的string是可以转换为byte数组或者rune数组但是其实byte对应的类型是uint8,而rune对应的数据类型就是in
- 二进制日志二进制日志中以“事件”的形式记录了数据库中数据的变化情况,对于MySQL数据库的灾难恢复起
- PHP输出JSON格式数据常用框架封装好的方法来输出JSON数据,但是手动去书写的时候却遇到了问题,因为输出的数据类型为字符串类型,导致不能
- 日期是许多 JavaScript 应用程序的基本组成部分,无论是在网页上显示当前日期还是处理用户输入以安排事件。但以清晰一致的格式显示日期对
- 一.字典的基本方法1.新建字典1)、建立一个空的字典>>> dict1={} >>> dict2=dic
- 1.ES6 解构[...arr, ...array]不改原数组值,生成新的数组。 2.遍历添加array.forEac