zoukankan      html  css  js  c++  java
  • python利用subprocess执行交互命令

    已经知道,os.system可以方便的利用python代码执行一些像ping、ipconfig之类的系统命令,但却只能得到命令执行是否成功,不能获得命令成功执行后的结果,像下面这样:

     1 >>> s = os.system("ping www.baidu.com")
     2 
     3 正在 Ping www.a.shifen.com [220.181.38.150] 具有 32 字节的数据:
     4 来自 220.181.38.150 的回复: 字节=32 时间=18ms TTL=52
     5 来自 220.181.38.150 的回复: 字节=32 时间=19ms TTL=52
     6 来自 220.181.38.150 的回复: 字节=32 时间=23ms TTL=52
     7 来自 220.181.38.150 的回复: 字节=32 时间=22ms TTL=52
     8 
     9 220.181.38.150 的 Ping 统计信息:
    10     数据包: 已发送 = 4,已接收 = 4,丢失 = 0 (0% 丢失),
    11 往返行程的估计时间(以毫秒为单位):
    12     最短 = 18ms,最长 = 23ms,平均 = 20ms
    13 >>> s
    14 0
    15 >>> type(s)
    16 <class 'int'>
    17 >>>

    在上面的代码中,利用os.system执行“ping www.baidu.com”并把结果赋值给s,但在下面可以看到,s的内容是int类型的0(表示命令执行成功),并不是命令的执行结果。如果只是需要判断命令是否执行成功,那完全可以使用这种方法,但如果想要获取命令执行的结果呢?可以使用subprocess这个模块。

    一:subprocess的作用

    subprocess模块主要用于创建子进程,并连接它们的输入、输出和错误管道,获取它们的返回状态。通俗地说就是通过这个模块,你可以在Python的代码里执行操作系统级别的命令,比如“ipconfig”、“du -sh”等等。subprocess模块替代了一些老的模块和函数,比如:

    os.system
    os.spawn*

    subprocess过去版本中的call()check_call()check_output()已经被run()方法取代了。run()方法为3.5版本新增。大多数情况下,推荐使用run()方法调用子进程,执行操作系统命令。在更高级的使用场景,你还可以使用Popen接口。其实run()方法在底层调用的就是Popen接口。

    二:subprocess的run方法

    subprocess.run(args, *, stdin=None, input=None, stdout=None, stderr=None, shell=False, timeout=None, check=False, encoding=None, errors=None)

    功能:执行args参数所表示的命令,等待命令结束,并返回一个CompletedProcess类型对象。

    下面是run参数的作用:

    args:表示要执行的命令。必须是一个字符串,字符串参数列表。
    
    stdin、stdout和stderr:子进程的标准输入、输出和错误。其值可以是subprocess.PIPE、subprocess.DEVNULL、一个已经存在的文件描述符、已经打开的文件对象或者None。subprocess.PIPE表示为子进程创建新的管道。subprocess.DEVNULL表示使用os.devnull。默认使用的是None,表示什么都不做。另外,stderr可以合并到stdout里一起输出。
    
    timeout:设置命令超时时间。如果命令执行时间超时,子进程将被杀死,并弹出TimeoutExpired异常。
    
    check:如果该参数设置为True,并且进程退出状态码不是0,则弹出CalledProcessError异常。
    
    encoding:如果指定了该参数,则stdin、stdout和stderr可以接收字符串数据,并以该编码方式编码。否则只接收bytes类型的数据。
    
    shell:如果该参数为True,将通过操作系统的shell执行指定的命令,如果执行命令时遇见权限不足的境况,可以将此参数设置为True

    注意,run()方法返回的不是我们想要的执行结果或相关信息,而是一个CompletedProcess类型对象。

    >>> r = subprocess.run("ping www.baidu.com")
    
    正在 Ping www.a.shifen.com [220.181.38.150] 具有 32 字节的数据:
    来自 220.181.38.150 的回复: 字节=32 时间=17ms TTL=52
    来自 220.181.38.150 的回复: 字节=32 时间=17ms TTL=52
    来自 220.181.38.150 的回复: 字节=32 时间=19ms TTL=52
    来自 220.181.38.150 的回复: 字节=32 时间=18ms TTL=52
    
    220.181.38.150 的 Ping 统计信息:
        数据包: 已发送 = 4,已接收 = 4,丢失 = 0 (0% 丢失),
    往返行程的估计时间(以毫秒为单位):
        最短 = 17ms,最长 = 19ms,平均 = 17ms
    >>> type(r)
    <class 'subprocess.CompletedProcess'>
    >>> r
    CompletedProcess(args='ping www.baidu.com', returncode=0)
    >>>

    可以看到,run方法的执行结果是一个CompletedProcess类型对象。

    下面是CompletedProcess类型对象的一些属性:

    args 启动进程的参数,通常是个列表或字符串。
    
    returncode 进程结束状态返回码。0表示成功状态。
    
    stdout 获取子进程的stdout。通常为bytes类型序列,None表示没有捕获值。如果你在调用run()方法时,设置了参数stderr=subprocess.STDOUT,则错误信息会和stdout一起输出,此时stderr的值是None。
    
    stderr() 获取子进程的错误信息。通常为bytes类型序列,None表示没有捕获值。
    
    check_returncode() 用于检查返回码。如果返回状态码不为零,弹出CalledProcessError异常。

    获取状态码:

    r = subprocess.run("ping www.baidu.com")
    
    正在 Ping www.a.shifen.com [220.181.38.150] 具有 32 字节的数据:
    来自 220.181.38.150 的回复: 字节=32 时间=35ms TTL=52
    来自 220.181.38.150 的回复: 字节=32 时间=29ms TTL=52
    来自 220.181.38.150 的回复: 字节=32 时间=16ms TTL=52
    来自 220.181.38.150 的回复: 字节=32 时间=18ms TTL=52
    
    220.181.38.150 的 Ping 统计信息:
        数据包: 已发送 = 4,已接收 = 4,丢失 = 0 (0% 丢失),
    往返行程的估计时间(以毫秒为单位):
        最短 = 16ms,最长 = 35ms,平均 = 24ms>>> r.returncode
    0

    获取命令执行后的内容:

    run()方法返回的是一个CompletedProcess类型对象,不能直接获取我们通常想要的结果。要获取命令执行的结果或者信息,在调用run()方法的时候,请指定stdout=subprocess.PIPE。

    >>> ret = subprocess.run('dir', shell=True, stdout=subprocess.PIPE)
    >>> ret
    CompletedProcess(args='dir', returncode=0, stdout=b' xc7xfdxb6xafxc6xf7 C xd6xd0xb5xc4xbexedxcaxc7 Windows 10
     xbexedxb5xc4xd0xf2xc1xd0xbaxc5xcaxc7 02DE-BFF0
    
     C:\Users\lwy xb5xc4xc4xbfxc2xbc
    
    2019/12/31  10:29    <DIR>          .
    2019/12/31  10:29    <DIR>          ..
    2019/10/16  10:27    <DIR>          .3T
    2019/09/23  20:31    <DIR>          .anaconda
    2019/10/07  13:14    <DIR>          .android
    2019/07/23  09:54    <DIR>          .astropy
    2019/12/28  19:01             4,807 .bash_history
    2019/09/26  18:19    <DIR>          .conda
    2019/09/26  18:19               151 .condarc
    2019/10/07  10:18    <DIR>          .config
    2019/11/02  11:50             1,126 .dbshell
    2019/07/31  16:49               181 .gitconfig
    2019/07/22  20:31    <DIR>          .ipython
    2019/09/23  16:15    <DIR>          .keras
    2019/11/06  21:47    <DIR>          .matplotlib
    2019/08/01  09:36                37 .minttyrc
    2019/10/06  20:53    <DIR>          .mitmproxy
    2019/10/01  15:20                 0 .mongorc.js
    2019/08/30  15:19    <DIR>          .oracle_jre_usage
    2019/07/21  23:57    <DIR>          .PyCharm2019.1
    2019/12/10  17:04                25 .python_history
    2019/07/31  16:04    <DIR>          .rdm
    2019/07/31  16:38                35 .rediscli_history
    2019/07/22  20:31    <DIR>          .spyder-py3
    2019/09/17  17:51             5,339 .viminfo
    2019/12/12  13:21    <DIR>          3D Objects
    2019/12/12  13:21    <DIR>          Contacts
    2019/12/31  13:41    <DIR>          Desktop
    2019/12/18  15:47    <DIR>          Documents
    2019/12/30  16:34    <DIR>          Downloads
    2019/12/12  13:21    <DIR>          Favorites
    2019/10/15  16:36    <DIR>          Funshion
    2019/12/12  13:21    <DIR>          Links
    2019/12/12  13:21    <DIR>          Music
    2019/07/21  23:58    <DIR>          OneDrive
    2019/12/12  13:21    <DIR>          Pictures
    2019/12/12  13:21    <DIR>          Saved Games
    2019/12/12  13:21    <DIR>          Searches
    2019/12/31  10:27    <DIR>          test22
    2019/12/12  13:21    <DIR>          Videos
                   9 xb8xf6xcexc4xbcxfe         11,701 xd7xd6xbdxda
                  31 xb8xf6xc4xbfxc2xbc 51,676,090,368 xbfxc9xd3xc3xd7xd6xbdxda
    ')
    >>> type(ret)
    <class 'subprocess.CompletedProcess'>
    >>>

    可以看到,这时候返回的内容就是命令的执行结果了,是一个CompletedProcess的类型,也可以通过指定编码使返回对象是一个字符串类型。

    >>> ret = subprocess.run('dir', shell=True, stdout=subprocess.PIPE).stdout.decode("gbk")
    >>> ret
    ' 驱动器 C 中的卷是 Windows 10
     卷的序列号是 02DE-BFF0
    
     C:\Users\lwy 的目录
    
    2019/12/31  10:29    <DIR>          .
    2019/12/31  10:29    <DIR>          ..
    2019/10/16  10:27    <DIR>          .3T
    2019/09/23  20:31    <DIR>          .anaconda
    2019/10/07  13:14    <DIR>          .android
    2019/07/23  09:54    <DIR>          .astropy
    2019/12/28  19:01             4,807 .bash_history
    2019/09/26  18:19    <DIR>          .conda
    2019/09/26  18:19               151 .condarc
    2019/10/07  10:18    <DIR>          .config
    2019/11/02  11:50             1,126 .dbshell
    2019/07/31  16:49               181 .gitconfig
    2019/07/22  20:31    <DIR>          .ipython
    2019/09/23  16:15    <DIR>          .keras
    2019/11/06  21:47    <DIR>          .matplotlib
    2019/08/01  09:36                37 .minttyrc
    2019/10/06  20:53    <DIR>          .mitmproxy
    2019/10/01  15:20                 0 .mongorc.js
    2019/08/30  15:19    <DIR>          .oracle_jre_usage
    2019/07/21  23:57    <DIR>          .PyCharm2019.1
    2019/12/10  17:04                25 .python_history
    2019/07/31  16:04    <DIR>          .rdm
    2019/07/31  16:38                35 .rediscli_history
    2019/07/22  20:31    <DIR>          .spyder-py3
    2019/09/17  17:51             5,339 .viminfo
    2019/12/12  13:21    <DIR>          3D Objects
    2019/12/12  13:21    <DIR>          Contacts
    2019/12/31  13:41    <DIR>          Desktop
    2019/12/18  15:47    <DIR>          Documents
    2019/12/30  16:34    <DIR>          Downloads
    2019/12/12  13:21    <DIR>          Favorites
    2019/10/15  16:36    <DIR>          Funshion
    2019/12/12  13:21    <DIR>          Links
    2019/12/12  13:21    <DIR>          Music
    2019/07/21  23:58    <DIR>          OneDrive
    2019/12/12  13:21    <DIR>          Pictures
    2019/12/12  13:21    <DIR>          Saved Games
    2019/12/12  13:21    <DIR>          Searches
    2019/12/31  10:27    <DIR>          test22
    2019/12/12  13:21    <DIR>          Videos
                   9 个文件         11,701 字节
                  31 个目录 51,681,050,624 可用字节
    '
    >>> type(ret)
    <class 'str'>
    >>>

    三:subprocess的Popen方法

    并不是所有的操作系统命令都像‘dir’或者‘ipconfig’那样单纯地返回执行结果,还有很多像‘python’这种交互式的命令,你要输入点什么,然后它返回执行的结果。subprocess中的Popen方法,可以执行一些交互性的命令。run方法也可以进行一些输入,不过很不方便,也不是以代码的形式驱动的,想要了解的同学可以看下文末大佬的原文。

    Popen的用法和参数与run()方法基本类同,但是它的返回值是一个Popen对象,而不是CompletedProcess对象。

    >>> r = subprocess.Popen("dir", shell=True)>>> type(r)
    <class 'subprocess.Popen'>
    >>> r
    <subprocess.Popen object at 0x000001921134EC48>
    >>>

    要‘python’命令功能,可以按下面的例子操作:

    import subprocess
    
    s = subprocess.Popen("python", stdout=subprocess.PIPE, stdin=subprocess.PIPE, shell=True)
    s.stdin.write(b"import os
    ")
    s.stdin.write(b"print(os.environ)")
    s.stdin.close()
    
    out = s.stdout.read().decode("GBK")
    s.stdout.close()
    print(out)

    另外,也可以把需要执行的后续命令卸载一个txt文件里,打开这个文件并赋值给stdin这个参数:

    f = open("111.txt", "r+")
    
    s = subprocess.Popen("python",stdout=subprocess.PIPE, stdin=f, shell=True)
    
    out = s.stdout.read().decode("utf-8")
    s.stdout.close()
    print(out)

    111.txt文件中的内容是:

    1 import os
    2 print(os.getcwd())

    注意:每行代码后面要加换行。

    参考文章:http://www.liujiangblog.com/course/python/55

    ********************不积跬步无以至千里********************

  • 相关阅读:
    socket的accept函数解析
    c socket(续)
    C socket指南
    网络字节序和本机字节序
    jar包
    RESTful API 设计指南[转]
    理解RESTful架构[转]
    c语言正则表达式
    Fedora设置中文
    创建框架结构的页面2
  • 原文地址:https://www.cnblogs.com/liangshian/p/12124738.html
Copyright © 2011-2022 走看看