zoukankan      html  css  js  c++  java
  • Python subprocess模块

    Python中可以执行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')
    

    随着Python版本的更新,过多的模块引起代码的复杂和冗余,因此Python引入了新模块subprocess,将以上几个模块中的功能集中到它当中,以后只需这一个模块就可以了

    subprocess的目的就是启动一个新的进程并且与之通信

    call:父进程等待子进程执行命令,返回子进程执行命令的状态码,如果出现错误,不进行报错

    这里说的返回执行命令的状态码的意思是:如果我们通过一个变量res = subprocess.call(['dir', shell=True])获取的执行结果,我们能获取到的子进程执行命令执行结果的状态码,即res=0/1执行成功或者不成功,并不是说看不到执行结果,在Python的console界面中我们是能够看到命令结果的,只是获取不到,想获取执行的返回结果,需要看check_output

    不进行报错解释:如果我们的命令在执行时,操作系统不识别,系统会返回一个错误,如:abc命令不存在,这个结果会在console界面显示出来,但是我们的Python解释器不会提示信息,如果想让Python解释器也进行报错,需要看check_call

    #!/usr/bin/env python
    # -*- coding:utf-8 -*-
    
    import subprocess
    
    print "################## subprocess.call ###############"
    print u"call方法调用系统命令进行执行,如果出错不报错"
    subprocess.call(['dir'],shell=True)
    

    注意:shell默认是False,在Linux下,shell=False时,Popen调用os.execvp()执行args指定的程序;shell=True时,如果args是字符串,Popen直接调用系统的shell来执行args指定的程序,如果args是一个序列,则args第一项是定义程序命令字符串,其他项是调用系统shell时的附加参数

    在Windows下,不论shell的值如何,Popen调用CreateProcess()执行args指定的外部程序,如果args是一个序列,则先用list2cmdline()转化为字符串,但需要注意的是,并不是MS Windows下所有的程序都可以使用list2cmdline()来转化字符串,在Windows下,调用脚本时需要写上shell=True

    返回结果

    ###### subprocess.call #######
    call方法调用系统命令进行执行,如果出错不报错
    
     D:ProgramPython 的目录
    
    2016/01/27  11:51             1,069 subprocessDemo.py
                   1 个文件          1,228 字节
    

      

    check_call:父进程等待子进程执行命令,返回执行命令的状态码,如果出现错误,进行报错(如果returncode不等于0,则举出错误subporcess.CallProcessError,该对象包含returncode属性,可用try...except...来检查)

    #!/usr/bin/env python
    # -*- coding:utf-8 -*-
    
    import subprocess
    
    print "2. ################## subprocess.check_call ##########"
    print u"check_call与call命令相同,区别是如果出错会报错"
    subprocess.check_call(['dir'],shell=True)
    subprocess.check_call(['abc'],shell=True)
    print u"call方法与check_call方法都知识执行并打印命令到输出终端,但是获取不到,如果想获取到结果使用check_output"
    

    执行结果:

    2. ################## subprocess.check_call ##########
    check_call与call命令相同,区别是如果出错会报错
     驱动器 D 中的卷没有标签。
     卷的序列号是 C6A1-5AD3
    
     D:ProgramPython 的目录
    
    2016/01/27  13:05    <DIR>          .
    2016/01/27  13:05    <DIR>          ..
    2016/01/27  10:44    <DIR>          .idea
    2016/01/27  11:23               159 log_analyse.py
    2016/01/27  13:05             1,329 subprocessDemo.py
    个文件          1,488 字节
    个目录 26,335,281,152 可用字节
    'abc' 不是内部或外部命令,也不是可运行的程序或批处理文件。                    这里是系统执行命令返回的系统报错
    Traceback (most recent call last):                              这里是Python解释器返回的报错
      File "D:/Program/Python/subprocessDemo.py", line 19, in <module>
        subprocess.check_call(['abc'],shell=True)
      File "C:Python27libsubprocess.py", line 540, in check_call
        raise CalledProcessError(retcode, cmd)
    subprocess.CalledProcessError: Command '['abc']' returned non-zero exit status 1
    

      

    check_output:父进程等待子进程执行命令,返回子进程向标准输出发送输出运行结果,检查退出信息,如果returncode不为0,则举出错误subprocess.CalledProcessError,该对象包含有returncode属性和output属性,output属性为标准输出的输出结果,可用try...except...来检查

    #!/usr/bin/env python
    # -*- coding:utf-8 -*-
    
    import subprocess
    
    print "3. ################## subprocess.check_output ##############"
    res1 = subprocess.call(['dir'],shell=True)
    res2 = subprocess.check_call(['dir'],shell=True)
    res3 = subprocess.check_output(['dir'],shell=True)
    print u"call结果:",res1
    print u"check_call结果:",res2
    print u"check_output结果:
    ",res3
    

    执行结果

    3. ################## subprocess.output ##############
     驱动器 D 中的卷没有标签。
     卷的序列号是 C6A1-5AD3
    
     D:ProgramPython 的目录
    
    2016/01/27  13:14    <DIR>          .
    2016/01/27  13:14    <DIR>          ..
    2016/01/27  10:44    <DIR>          .idea
    2016/01/27  11:23               159 log_analyse.py
    2016/01/27  13:14             1,324 subprocessDemo.py
    个文件          1,483 字节
    个目录 26,334,232,576 可用字节
     驱动器 D 中的卷没有标签。
     卷的序列号是 C6A1-5AD3
    
     D:ProgramPython 的目录
    
    2016/01/27  13:14    <DIR>          .
    2016/01/27  13:14    <DIR>          ..
    2016/01/27  10:44    <DIR>          .idea
    2016/01/27  11:23               159 log_analyse.py
    2016/01/27  13:14             1,324 subprocessDemo.py
    个文件          1,483 字节
    个目录 26,334,232,576 可用字节
    call结果: 0
    check_call结果: 0
    check_output结果:
     驱动器 D 中的卷没有标签。
     卷的序列号是 C6A1-5AD3
    
     D:ProgramPython 的目录
    
    2016/01/27  13:14    <DIR>          .
    2016/01/27  13:14    <DIR>          ..
    2016/01/27  10:44    <DIR>          .idea
    2016/01/27  11:23               159 log_analyse.py
    2016/01/27  13:14             1,324 subprocessDemo.py
    个文件          1,483 字节
    个目录 26,334,232,576 可用字节
    

      可见,call/check_call返回值都是命令的执行状态码,而check_output返回的是命令的执行结果;

    如果在执行命令的时候,有相关参数,将程序名(即命令)和所带的参数一起放在一个列表中传递给相关方法即可,例如:

    >>> import subprocess
    >>> retcode = subprocess.call(["ls", "-l"])
    >>> print retcode
    0
    

      

    Popen:

    实际上,subprocess模块只定义了一个类:Popen。上面的几个函数都是基于Popen的封装(wrapper),从Python2.4开始使用Popen来创建进程,用于连接到子进程的标准输入/输出/错误中去,还可以得到子进程的返回值,这些封装的目的在于让我们容易使用子进程,当我们想要更个性化我们的需求的时候,就要转向Popen类,该类生成的对象用来代表子进程

    构造函数如下:

    subprocess.Popen(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)
    

    与上面的封装不同,Popen对象创建之后,主进程不会等待子进程的完成,我们必须调用对象的wait()方法,父进程才会等待(也就是阻塞Block)

    不等待的子进程

    #!/usr/bin/env python
    import subprocess
    
    child = subprocess.Popen(['ping','-c','4','www.baidu.com'])
    print 'hello'
    

    输出结果:

    [root@localhost script]# python sub.py 
    hello
    [root@localhost script]# PING www.a.shifen.com (61.135.169.125) 56(84) bytes of data.
    64 bytes from 61.135.169.125: icmp_seq=1 ttl=55 time=2.04 ms
    64 bytes from 61.135.169.125: icmp_seq=2 ttl=55 time=1.58 ms
    64 bytes from 61.135.169.125: icmp_seq=3 ttl=55 time=2.22 ms
    64 bytes from 61.135.169.125: icmp_seq=4 ttl=55 time=2.13 ms
    
    --- www.a.shifen.com ping statistics ---
    4 packets transmitted, 4 received, 0% packet loss, time 3008ms
    rtt min/avg/max/mdev = 1.580/1.995/2.220/0.251 ms
    

    可以看出,Python并没有等到child子进程执行的Popen操作完成就执行了print操作

    添加子进程等待

    #!/usr/bin/env python
    import subprocess
    
    child = subprocess.Popen(['ping','-c','4','www.baidu.com'])  #创建一个子进程,进程名为child,执行操作ping -c 4 www.baidu.com
    child.wait()                             #子进程等待
    print 'hello'
    

    执行结果:

    [root@localhost script]# python sub.py 
    PING www.a.shifen.com (61.135.169.125) 56(84) bytes of data.
    64 bytes from 61.135.169.125: icmp_seq=1 ttl=55 time=1.82 ms
    64 bytes from 61.135.169.125: icmp_seq=2 ttl=55 time=1.65 ms
    64 bytes from 61.135.169.125: icmp_seq=3 ttl=55 time=1.99 ms
    64 bytes from 61.135.169.125: icmp_seq=4 ttl=55 time=2.08 ms
    
    --- www.a.shifen.com ping statistics ---
    4 packets transmitted, 4 received, 0% packet loss, time 3009ms
    rtt min/avg/max/mdev = 1.656/1.889/2.082/0.169 ms
    hello
    

    可以看出,Python执行print操作是在child子进程执行完成以后才进行的

    此外,你还可以在父进程中对子进程进行其他操作,比如我们上面例子中的child对象:

    child.poll() # 检查子进程状态
    child.kill() # 终止子进程
    child.send_signal() # 向子进程发送信号
    child.terminate() # 终止子进程
    ps: 子进程的PID存储在child.pid
    

      

    子进程文本流控制

    子进程的标准输入,标准输出,标准错误如下属性属性分别表示:

    child.stdin  |   child.stdout   |   child.stderr

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

    例1 
    #!/usr/bin/env python
    
    import subprocess
    
    child = subprocess.Popen(['ls','-l'],stdout=subprocess.PIPE)    #将标准输出定向输出到subprocess.PIPE
    print child.stdout.read()   #使用 child.communicate()  也可
    

      

    [root@localhost script]# python sub.py 
    total 12-rw-r--r--. 1 root root  36 Jan 23 07:38 analyse.sh
    -rw-r--r--. 1 root root 446 Jan 25 19:35 sub.py
    

      

    例2
    #!/usr/bin/env python
    import subprocess
    
    child1 = subprocess.Popen(['cat','/etc/passwd'],stdout=subprocess.PIPE)
    child2 = subprocess.Popen(['grep','root'],stdin=child1.stdout,stdout=subprocess.PIPE)
    
    print child2.communicate
    

      

    ('root:x:0:0:root:/root:/bin/bash
    , None)
    

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

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

    子进程命令解释

    在上面的例子中,我们创建子进程时,全部调用的Python进行解释,但是Python并没有将所有命令全部解释,当Python不进行解释时,就需要调用系统来进行执行

    #!/usr/bin/env python
    
    import subprocess
    
    subprocess.Popen(['ls','-l'])
    
    subprocess.Popen(['ifconfig|grep 127.0.0.1'],shell=True)
    

      

    >>> subprocess.Popen(['ifconfig|grep 127.0.0.1'],shell=True)
    <subprocess.Popen object at 0x7f25eb0c1350>
    >>>           inet addr:127.0.0.1  Mask:255.0.0.0
    

      

    转载

  • 相关阅读:
    Linux04:压缩与解压
    Linux03:基本权限与初始权限
    Linux02:基本命令、查看文件、链接命令
    Linux01:虚拟机配置与系统安装
    分库分表和数据库分片方案
    mysql的锁
    redo log和undo log、事务
    Android : 代码多维度管理(产品风味)
    Android : 网络adb配置及有线端口占用解决方法
    Linux学习: 触摸屏驱动
  • 原文地址:https://www.cnblogs.com/yyf573462811/p/9586177.html
Copyright © 2011-2022 走看看