模块-Subprocess

 

一、介绍

在学习这个模块前,我们先用Python的help()函数查看一下subprocess模块是干嘛的:

DESCRIPTION
 This module allows you to spawn processes, connect to their
 input/output/error pipes, and obtain their return codes.

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

该模块旨在替换几个较旧的模块和功能:os.system、os.spawn*

注意:使用这个模块之前要先引入该模块。

二、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)

主要参数说明:
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, stderr=subprocess.STDOUT)

cmd:标准像子进程传入需要执行的shell命令,如:ls -al
subprocess.PIPE:在创建Popen对象时,subprocess.PIPE可以初始化为stdin, stdout或stderr的参数,表示与子进程通信的标准输入流,标准输出流以及标准错误。
subprocess.STDOUT:作为Popen对象的stderr的参数,表示将标准错误通过标准输出流输出。

四、Popen类拥有的方法及属性

1、Popen.pid

获取子进程的进程ID。

2、Popen.returncode

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

3、communicate(input=None)

官方解释:

Interact with process: Send data to stdin. Read data from
 stdout and stderr, until end-of-file is reached. Wait for
 process to terminate. The optional input argument should be a
 string to be sent to the child process, or None, if no data
 should be sent to the child.

communicate() returns a tuple (stdout, stderr).

与子进程进行交互,像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()是一样的,表示杀死子进程。

 

import  subprocess
retcode = subprocess.call(["ls", "-l"]) #执行命令,返回命令执行状态 , 0 or 非0
subprocess.check_call(["ls", "-l"]) #执行命令,如果命令结果为0,就正常返回,否则抛异常
print(subprocess.getstatusoutput('ls /bin/ls'))#接收字符串格式命令,返回元组形式,第1个元素是执行状态,第2个是命令结果
print(subprocess.getoutput('ls /bin/ls'))#接收字符串格式命令,并返回结果
print(res=subprocess.check_output(['ls','-l']))#执行命令,并返回结果,注意是返回结果,不是打印,下例结果返回给res

#上面那些方法,底层都是封装的subprocess.Popen
poll()
wait()
terminate() 杀掉所启动进程
communicate() 等待任务结束
stdin 标准输入
stdout 标准输出
stderr 标准错误
pid     The process ID of the child process.

p = subprocess.Popen("df -h|grep disk",stdin=subprocess.PIPE,stdout=subprocess.PIPE,shell=True)
p.stdout.read()

 

import subprocess
subprocess.run(["ls", "-l"])  # doesn't capture output
subprocess.run("exit 1", shell=True, check=True)
subprocess.run(["ls", "-l", "/dev/null"], stdout=subprocess.PIPE)

调用subprocess.run(...)是推荐的常用方法,在大多数情况下能满足需求,但如果你可能需要进行一些复杂的与系统的交互的话,你还可以用subprocess.Popen(),语法如下:

import subprocess
p = subprocess.Popen("find / -size +1000000 -exec ls -shl {} \;",shell=True,stdout=subprocess.PIPE)
print(p.stdout.read())

 

可用参数:

  • args:shell命令,可以是字符串或者序列类型(如:list,元组)
  • bufsize:指定缓冲。0 无缓冲,1 行缓冲,其他 缓冲区大小,负值 系统缓冲
  • stdin, stdout, stderr:分别表示程序的标准输入、输出、错误句柄
  • preexec_fn:只在Unix平台下有效,用于指定一个可执行对象(callable object),它将在子进程运行之前被调用
  • close_sfs:在windows平台下,如果close_fds被设置为True,则新创建的子进程将不会继承父进程的输入、输出、错误管道。
    所以不能将close_fds设置为True同时重定向子进程的标准输入、输出与错误(stdin, stdout, stderr)。
  • shell:同上
  • cwd:用于设置子进程的当前目录
  • env:用于指定子进程的环境变量。如果env = None,子进程的环境变量将从父进程中继承。
  • universal_newlines:不同系统的换行符不同,True -> 同意使用 \n
  • startupinfo与createionflags只在windows下有效
    将被传递给底层的CreateProcess()函数,用于设置子进程的一些属性,如:主窗口的外观,进程的优先级等等

终端输入的命令分为两种:

  • 输入即可得到输出,如:ifconfig
  • 输入进行某环境,依赖再输入,如:python

需要交互的命令示例:

import subprocess
obj = subprocess.Popen(["python"], stdin=subprocess.PIPE, stdout=subprocess.PIPE, stderr=subprocess.PIPE)
obj.stdin.write(b'print 1 \n')
obj.stdin.write(b'print 2 \n')
obj.stdin.write(b'print 3 \n')
obj.stdin.write(b'print 4 \n')
out_error_list = obj.communicate(timeout=10)
print(out_error_list)

五、执行系统命令

 可以执行shell命令的相关模块和函数有:

  • os.system
  • os.spawn*
  • os.popen*          --废弃
  • popen2.*           --废弃
  • commands.*      --废弃,3.x中被移除
import commands
result = commands.getoutput('cmd')
result = commands.getstatus('cmd')
result = commands.getstatusoutput('cmd')

 

六、进程通信实例

 

import subprocess
import os

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()
fp = open('E:/PycharmProjects/PythonStudy/test/tt', 'r')
ipList = fp.readlines()
fp.close()
fp = open('E:/PycharmProjects/PythonStudy/test/tt1', 'a')
print(ipList)
for i in ipList:
    i = i.strip()
    result = shell.runCmd('ping ' + i)
    if result[0] == 0:
        w = i + ' : 0'
        fp.write(w + '\n')
    else:
        w = i + ' : 1'
        fp.write(w + '\n')

fp.close()

 

subprocess实现sudo 自动输入密码

import subprocess

def mypass():
    mypass = '123'  # or get the password from anywhere
    return mypass
echo = subprocess.Popen(['echo', mypass()],
                        stdout=subprocess.PIPE,
                        )
sudo = subprocess.Popen(['sudo', '-S', 'iptables', '-L'],
                        stdin=echo.stdout,
                        stdout=subprocess.PIPE,
                        )
end_of_pipe = sudo.stdout
print("Password ok \n Iptables Chains %s" %end_of_pipe.read())

 

posted @ 2018-09-16 12:49  航松先生  阅读(177)  评论(0)    收藏  举报