subprocess模块

subprocess 到底是用来干什么的?

subprocess 允许你去创建一个新的进程让其执行另外的程序,并与它进行通信,获取标准的输入、标准输出、标准错误以及返回码等。

在Windows上也可以使用os.system()这个函数来执行一些dos命令,但是这个命令只能拿到返回码,拿不到标准输出,标准错误,所以通常使用的subprocess模块中的Popen类来实现。

我们能从Python官方文档里读到应该用subprocess 模块来运行系统命令,subprocess模块允许我们创建子进程,连接他们的输入/输出/错误管道,还有获得返回值。
subprocess模块打算来替代几个过时的模块和函数,比如:os.system, os.spawn*, os.popen*, popen2.*命令。

Popen类

subprocess模块中定义了一个Popen类,通过它可以来创建进程,并与其进行复杂的交互。查看一下它的构造函数:

__init__(self, args, bufsize=0, executable=None, 
stdin=None, stdout=None, stderr=None, preexec_fn=None, 
close_fds=False, shell=False, cwd=None, env=None, 
universal_newlines=False, startupinfo=None, 
creationflags=0)

Python subprocess获取输出内容和返回码 python subprocess popen_d3

主要参数说明:

args:args should be a string, or a sequence of program arguments.也就是说必须是一个字符串或者序列类型(如:字符串、list、元组),用于指定进程的可执行文件及其参数。如果是一个序列类型参数,则序列的第一个元素通常都必须是一个可执行文件的路径。当然也可以使用executeable参数来指定可执行文件的路径。

stdin,stdout,stderr:分别表示程序的标准输入、标准输出、标准错误。有效的值可以是PIPE,存在的文件描述符,存在的文件对象或None,如果为None需从父进程继承过来,stdout可以是PIPE,表示对子进程创建一个管道,stderr可以是STDOUT,表示标准错误数据应该从应用程序中捕获并作为标准输出流stdout的文件句柄。

shell:如果这个参数被设置为True,程序将通过shell来执行。 

env:它描述的是子进程的环境变量。如果为None,子进程的环境变量将从父进程继承而来。

创建Popen类的实例对象

res = subprocess.Popen(cmd, shell=True, stdout=subprocess.PIPE, stdin = subprocess.PIPE ,stderr=subprocess.PIPE)

cmd:标准像子进程传入需要执行的shell命令,如:ls -al ‘dir’

subprocess.PIPE:在创建Popen对象时,subprocess.PIPE可以初始化为stdin, stdout或stderr的参数,表示与子进程通信的标准输入流,标准输出流以及标准错误。

subprocess.STDOUT:可以作为Popen对象的stderr的参数,表示将标准错误通过标准输出流输出。

一些常用的Popen方法和属性

import subprocess
res=subprocess.Popen('dir',shell=True,stdout=subprocess.PIPE,stdin=subprocess.PIPE,stderr=subprocess.PIPE)
res.stdout.read()

再一次读取管道的结果 res 为空

>>> res.stdout.read()
b''

输入错误的cmd

>>> res=subprocess.Popen('23154nkdaslafsd',shell=True,stdout=subprocess.PIPE,stdin=subprocess.PIPE,stderr=subprocess.PIPE)
>>> res.stdout.read()
b''
>>> res.stderr.read()
b"'23154nkdaslafsd' \xb2\xbb\xca\xc7\xc4\xda\xb2\xbf\xbb\xf2\xcd\xe2\xb2\xbf\xc3\xfc\xc1\xee\xa3\xac\xd2\xb2\xb2\xbb\xca\xc7\xbf\xc9\xd4\xcb\xd0\xd0\xb5\xc4\xb3\xcc\xd0\xf2\r\n\xbb\xf2\xc5\xfa\xb4\xa6\xc0\xed\xce\xc4\xbc\xfe\xa1\xa3\r\n"

Popen类拥有的方法及属性

1、Popen.pid 

获取子进程的进程ID。

2、Popen.returncode 

获取进程的返回码。如果进程未结束,将返回None。

3、communicate(input=None) 

与子进程进行交互,像stdin发送数据,并从stdout和stderr读出数据存在一个tuple中并返回。 参数input应该是一个发送给子进程的字符串,如果未指定数据,将传入None。

4、poll() 

检查子进程是否结束,并返回returncode属性。

5、wait()

Wait for child process to terminate. Returns returncode attribute.(等待子进程执行结束,并返回returncode属性,如果为0表示执行成功。)

6、send_signal( sig)

Send a signal to the process(发送信号给子进程。)

7、terminate()

Terminates the process(终止子进程。windows下将调用Windows API TerminateProcess()来结束子进程。)

8、kill() 

官方文档对这个函数的解释跟terminate()是一样的,表示杀死子进程。

进程通信实例1

打开一个只有ip地址的文本文件,读取其中的ip,然后进行ping操作,并将ping结果写入ping.txt文件中。 
首先创建一个子进程res,传入要执行的shell命令,并获得标准输出流、返回码等。

import subprocess

class Shell(object):
    def runCmd(self, cmd):
        res = subprocess.Popen(cmd, shell=True, stdout=subprocess.PIPE, stderr=subprocess.STDOUT)
        sout, serr = res.communicate()
        # print(res.returncode, sout, serr, res.pid)
        return res.returncode, sout, serr, res.pid

shell = Shell()
fp = open('ip.txt', 'r',encoding='utf8')
ipList = fp.readlines()
fp.close()
fp = open('ping.txt', 'w',encoding='utf8')
print(ipList)
for i in ipList:
    i = i.strip()
    result = shell.runCmd('ping ' + i)
    if result[0] == 0:      #没有ping 到结果
        w = i + ' : ping到结果了'
        print(result)
        fp.write(w + '\n')

    else:           ##ping 到结果了
        w = i + ' : ping失败'
        print(result)
        fp.write(w + '\n')

fp.close()

返回结果:

Python subprocess获取输出内容和返回码 python subprocess popen_d3_02

Python subprocess获取输出内容和返回码 python subprocess popen_子进程_03

['www.baidu.com\n', 'www.taobao.com\n', 'www.cnblogs.com\n', 'www.jioghidgjnia.com']
(0, b'\r\n\xd5\xfd\xd4\xda Ping www.baidu.com [183.232.231.174] \xbe\xdf\xd3\xd0 32 \xd7\xd6\xbd\xda\xb5\xc4\xca\xfd\xbe\xdd:\r\n\xc0\xb4\xd7\xd4 183.232.231.174 \xb5\xc4\xbb\xd8\xb8\xb4: \xd7\xd6\xbd\xda=32 \xca\xb1\xbc\xe4=35ms TTL=54\r\n\xc0\xb4\xd7\xd4 183.232.231.174 \xb5\xc4\xbb\xd8\xb8\xb4: \xd7\xd6\xbd\xda=32 \xca\xb1\xbc\xe4=36ms TTL=54\r\n\xc0\xb4\xd7\xd4 183.232.231.174 \xb5\xc4\xbb\xd8\xb8\xb4: \xd7\xd6\xbd\xda=32 \xca\xb1\xbc\xe4=44ms TTL=54\r\n\xc0\xb4\xd7\xd4 183.232.231.174 \xb5\xc4\xbb\xd8\xb8\xb4: \xd7\xd6\xbd\xda=32 \xca\xb1\xbc\xe4=68ms TTL=54\r\n\r\n183.232.231.174 \xb5\xc4 Ping \xcd\xb3\xbc\xc6\xd0\xc5\xcf\xa2:\r\n    \xca\xfd\xbe\xdd\xb0\xfc: \xd2\xd1\xb7\xa2\xcb\xcd = 4\xa3\xac\xd2\xd1\xbd\xd3\xca\xd5 = 4\xa3\xac\xb6\xaa\xca\xa7 = 0 (0% \xb6\xaa\xca\xa7)\xa3\xac\r\n\xcd\xf9\xb7\xb5\xd0\xd0\xb3\xcc\xb5\xc4\xb9\xc0\xbc\xc6\xca\xb1\xbc\xe4(\xd2\xd4\xba\xc1\xc3\xeb\xce\xaa\xb5\xa5\xce\xbb):\r\n    \xd7\xee\xb6\xcc = 35ms\xa3\xac\xd7\xee\xb3\xa4 = 68ms\xa3\xac\xc6\xbd\xbe\xf9 = 45ms\r\n', None, 9948)
(0, b'\r\n\xd5\xfd\xd4\xda Ping www.taobao.com [223.99.232.254] \xbe\xdf\xd3\xd0 32 \xd7\xd6\xbd\xda\xb5\xc4\xca\xfd\xbe\xdd:\r\n\xc0\xb4\xd7\xd4 223.99.232.254 \xb5\xc4\xbb\xd8\xb8\xb4: \xd7\xd6\xbd\xda=32 \xca\xb1\xbc\xe4=39ms TTL=53\r\n\xc0\xb4\xd7\xd4 223.99.232.254 \xb5\xc4\xbb\xd8\xb8\xb4: \xd7\xd6\xbd\xda=32 \xca\xb1\xbc\xe4=27ms TTL=53\r\n\xc0\xb4\xd7\xd4 223.99.232.254 \xb5\xc4\xbb\xd8\xb8\xb4: \xd7\xd6\xbd\xda=32 \xca\xb1\xbc\xe4=27ms TTL=53\r\n\xc0\xb4\xd7\xd4 223.99.232.254 \xb5\xc4\xbb\xd8\xb8\xb4: \xd7\xd6\xbd\xda=32 \xca\xb1\xbc\xe4=59ms TTL=53\r\n\r\n223.99.232.254 \xb5\xc4 Ping \xcd\xb3\xbc\xc6\xd0\xc5\xcf\xa2:\r\n    \xca\xfd\xbe\xdd\xb0\xfc: \xd2\xd1\xb7\xa2\xcb\xcd = 4\xa3\xac\xd2\xd1\xbd\xd3\xca\xd5 = 4\xa3\xac\xb6\xaa\xca\xa7 = 0 (0% \xb6\xaa\xca\xa7)\xa3\xac\r\n\xcd\xf9\xb7\xb5\xd0\xd0\xb3\xcc\xb5\xc4\xb9\xc0\xbc\xc6\xca\xb1\xbc\xe4(\xd2\xd4\xba\xc1\xc3\xeb\xce\xaa\xb5\xa5\xce\xbb):\r\n    \xd7\xee\xb6\xcc = 27ms\xa3\xac\xd7\xee\xb3\xa4 = 59ms\xa3\xac\xc6\xbd\xbe\xf9 = 38ms\r\n', None, 1084)
(0, b'\r\n\xd5\xfd\xd4\xda Ping www.cnblogs.com [42.121.252.58] \xbe\xdf\xd3\xd0 32 \xd7\xd6\xbd\xda\xb5\xc4\xca\xfd\xbe\xdd:\r\n\xc0\xb4\xd7\xd4 42.121.252.58 \xb5\xc4\xbb\xd8\xb8\xb4: \xd7\xd6\xbd\xda=32 \xca\xb1\xbc\xe4=8ms TTL=91\r\n\xc0\xb4\xd7\xd4 42.121.252.58 \xb5\xc4\xbb\xd8\xb8\xb4: \xd7\xd6\xbd\xda=32 \xca\xb1\xbc\xe4=25ms TTL=91\r\n\xc0\xb4\xd7\xd4 42.121.252.58 \xb5\xc4\xbb\xd8\xb8\xb4: \xd7\xd6\xbd\xda=32 \xca\xb1\xbc\xe4=19ms TTL=91\r\n\xc0\xb4\xd7\xd4 42.121.252.58 \xb5\xc4\xbb\xd8\xb8\xb4: \xd7\xd6\xbd\xda=32 \xca\xb1\xbc\xe4=10ms TTL=91\r\n\r\n42.121.252.58 \xb5\xc4 Ping \xcd\xb3\xbc\xc6\xd0\xc5\xcf\xa2:\r\n    \xca\xfd\xbe\xdd\xb0\xfc: \xd2\xd1\xb7\xa2\xcb\xcd = 4\xa3\xac\xd2\xd1\xbd\xd3\xca\xd5 = 4\xa3\xac\xb6\xaa\xca\xa7 = 0 (0% \xb6\xaa\xca\xa7)\xa3\xac\r\n\xcd\xf9\xb7\xb5\xd0\xd0\xb3\xcc\xb5\xc4\xb9\xc0\xbc\xc6\xca\xb1\xbc\xe4(\xd2\xd4\xba\xc1\xc3\xeb\xce\xaa\xb5\xa5\xce\xbb):\r\n    \xd7\xee\xb6\xcc = 8ms\xa3\xac\xd7\xee\xb3\xa4 = 25ms\xa3\xac\xc6\xbd\xbe\xf9 = 15ms\r\n', None, 9720)
(1, b'Ping \xc7\xeb\xc7\xf3\xd5\xd2\xb2\xbb\xb5\xbd\xd6\xf7\xbb\xfa www.jioghidgjnia.com\xa1\xa3\xc7\xeb\xbc\xec\xb2\xe9\xb8\xc3\xc3\xfb\xb3\xc6\xa3\xac\xc8\xbb\xba\xf3\xd6\xd8\xca\xd4\xa1\xa3\r\n', None, 2492)

View Code

 

Python subprocess获取输出内容和返回码 python subprocess popen_子进程_04

 

Python subprocess获取输出内容和返回码 python subprocess popen_子进程_05

进程通信实例2

命令交互,不断从键盘接受命令执行,给出执行结果,直到用户输入exit或者bye退出命令交互。

import subprocess
class Shell(object):
    def runCmd(self, cmd):
        res = subprocess.Popen(cmd, shell=True, stdout=subprocess.PIPE, stderr=subprocess.STDOUT)
        sout, serr = res.communicate()
        return res.returncode, sout, serr, res.pid

shell = Shell()
while True:
    inp = input('>>>')
    if inp == 'exit' or inp == 'bye':
        break
    else:
        result = shell.runCmd(inp)
        print("返回码:", result[0])
        print("标准输出:", result[1].decode('gbk'))
        print("标准错误:", result[2])

输出结果:

>>>dir
返回码: 0
标准输出:  驱动器 D 中的卷是 DATA
 卷的序列号是 C2A2-1B5C

 D:\360Downloads\Python编程\老男孩Python全栈\Python基础到进阶\Python模块\subprocess模块 的目录

2019/05/23 周四  09:33    <DIR>          .
2019/05/23 周四  09:33    <DIR>          ..
2019/05/23 周四  09:22                68 ip.txt
2019/05/23 周四  09:27               140 ping.txt
2019/05/23 周四  09:28               832 进程通信实例1.py
2019/05/23 周四  09:33               563 进程通信实例2.py
               4 个文件          1,603 字节
               2 个目录 112,898,076,672 可用字节

标准错误: None
>>>