subprocess.Popen用法

背景:

最近需要抓取一个程序的运行log,但发现os.popen去执行程序,只能抓取到标准输出的log,错误输出的log没法抓取到。导致只能想其他办法,后发现subprocess库的Popen方法解决了这个问题,所以特此来归纳学习一下

 

subprocess介绍:

subprocess 模块允许我们启动一个新进程,并连接到它们的输入/输出/错误管道,从而获取返回值

Popen 是 subprocess的核心,子进程的创建和管理都靠它处理。

构造函数:

class subprocess.Popen(args, bufsize=-1, executable=None, stdin=None, stdout=None, stderr=None, 
preexec_fn=None, close_fds=True, shell=False, cwd=None, env=None, universal_newlines=False, 
startupinfo=None, creationflags=0,restore_signals=True, start_new_session=False, pass_fds=(),
*, encoding=None, errors=None)

下面挑选一些常用参数来说明

args

agrs参数可以接收三种形式的值:

1、程序参数的序列(以list的形式)

subprocess.Popen(['python','test.py'])

2、字符串

subprocess.Popen('python test.py')

3、(可执行文件的)路径

subprocess.Popen('test.bat')

 

shell

参数 shell (默认为 False)指定是否使用 shell 执行程序。如果 shell 为 True,更推荐将 args 作为字符串传递而非序列。

在 POSIX,当 shell=True, shell 默认为 /bin/sh。如果 args 是一个字符串,此字符串指定将通过 shell 执行的命令。这意味着字符串的格式必须和在命令提示符中所输入的完全相同。这包括,例如,引号和反斜杠转义包含空格的文件名。如果 args 是一个序列,第一项指定了命令,另外的项目将作为传递给 shell (而非命令) 的参数对待。

在 Windows,使用 shell=True,环境变量 COMSPEC 指定了默认 shell。在 Windows 你唯一需要指定 shell=True 的情况是你想要执行内置在 shell 中的命令(例如 dir 或者 copy)。在运行一个批处理文件或者基于控制台的可执行文件时,不需要 shell=True

当你需要使用 shell 中特有的命令时,需要加上 shell=True

 

stdin,stdout,stderr

stdin:标准输入

stdout:标准输出

stderr:标准错误

合法的值有PIPE,DEVNULL,一个存在的文件描述符(一个正整数),一个存在的文件对象,以及None

PIPE:为文本流提供一个缓存区,可将stdin、stdout、stderr的文件都输出到缓存去中

DEVNULL:等同/dev/null,表示输出内容全部丢弃不保存

例子:

import subprocess

sbpss = subprocess.Popen('python test.py',stdout=subprocess.PIPE,stderr=subprocess.PIPE)
print(sbpss.stdout.read())
print(sbpss.stderr.read())

输出如下:

 

如果想同时捕获标准输出和标准错误输出,可以将stderr设置为subprocess.STDOUT,表示将stderr标准错误输出重定向到stdout标准输出中,同时标准输出又重定向到PIPE中

下面我将shell打开,然后故意将echo写错为ech,就会输出标准错误

import subprocess

sbpss = subprocess.Popen('ech test',shell=True,stdout=subprocess.PIPE,stderr=subprocess.STDOUT)
print(sbpss.stdout.read())

打印如下:

可以看到上面输出都是byte形式,无法直观看到输出,可以用以下3个方法解决

1、encoding=''

import subprocess

sbpss = subprocess.Popen('echo 你好',shell=True,stdout=subprocess.PIPE,stderr=subprocess.PIPE,encoding='gbk')
print(sbpss.stdout.read())

2、decode()

import subprocess

sbpss = subprocess.Popen('echo 你好',shell=True,stdout=subprocess.PIPE,stderr=subprocess.PIPE)
print(sbpss.stdout.read().decode('gbk'))

3、text=True(推荐,不需要考虑编码格式)

import subprocess
sbpss = subprocess.Popen('echo 你好',shell=True,stdout=subprocess.PIPE,stderr=subprocess.PIPE,text=True)
print(sbpss.stdout.read())

 

 

 cwd

用于设置子进程的当前目录

如下:需要在其它路径下创建一个文件夹

import subprocess

sbpss = subprocess.Popen('mkdir test',shell=True,cwd='D:\prj_test\subprocess_test')

可以看到已经在D:\prj_test\subprocess_test下新建了一个test文件夹

 

 

 

 

env

为子进程设置环境变量,默认为None,子进程的环境变量从父进程中继承

env 参数的值必须是一个字典类型。设置了 env 参数之后,不仅可以在命令中使用,也可以在 bat 或者 sh 脚本中使用

import subprocess

sbpss = subprocess.Popen('echo %name% 是 %gender%的',shell=True,stdout=subprocess.PIPE,text=True,env={'name':'小明','gender':''})
print(sbpss.stdout.read())

输出如下

 

注意,示例代码中环境变量的写法是 windows系统的写法,在 unix 环境下你应该使用 $name来替代%name%

 

communicate(input,timeout)方法

有的时候,我们需要在子进程中实现一些输入,子进程才能进行下一步,此时就需要用到communicate()方法,将输入传输到子进程之中

复制代码
###name.py###
name = input('what is name?\n')
print(f'hi,{name}')


import subprocess

sbpss = subprocess.Popen('python name.py',shell=True,stdin=subprocess.PIPE)
sbpss.communicate('xiaoming'.encode('utf-8'))
复制代码

输出结果:

 

 

在name.py中,使用input方法来接收用户输入,同时在popen中设置stdin参数为一个通道,这样就用可以通过communicate('xiaoming'.encode('utf-8')),来传入用户的输入到子进程中,子进程接着向下执行

communicate 方法返回两个值,文档里面说到这两个值分别为 stdout 以及 stderr。当你在 Popen 参数中设置了二者为 PIPE 时,就可以返回相应的结果了,否则将会输出两个 None

import subprocess

sbpss = subprocess.Popen('python name.py',shell=True,stdin=subprocess.PIPE,stdout=subprocess.PIPE,stderr=subprocess.PIPE)
out,err = sbpss.communicate('xiaoming'.encode('utf-8'))
print('标准输出:'+out.decode())
print('标准错误:'+err.decode())

输出结果:

 

 

returncode属性

对于一个进程来说,在其结束时往往会返回一个 exit code,通常情况下,code 为 0 表示一切正常,否则就是出现错误。

在 Popen 中,同样也有 returncode 来返回子程序的 exit code。不过这个值必须要在 communicate 方法之后才能获取到

import subprocess

sbpss = subprocess.Popen('echo hi',shell=True)
print(sbpss.returncode)
sbpss.communicate()
print(sbpss.returncode)

 

 

 

参考资料:https://ld246.com/article/1577762914087、https://www.runoob.com/w3cnote/python3-subprocess.html

posted @   测试-13  阅读(2687)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 10年+ .NET Coder 心语 ── 封装的思维:从隐藏、稳定开始理解其本质意义
· 提示词工程——AI应用必不可少的技术
· 地球OL攻略 —— 某应届生求职总结
· 字符编码:从基础到乱码解决
· SpringCloud带你走进微服务的世界
点击右上角即可分享
微信分享提示