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

    subprocess模块

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

      在subprocess模块中启动子进程,最简单的方式就是使用这里的便利函数。当这些便利函数不能满足函数时,在使用底层的Popen类。便利函数包括call、check_all与check_output,run(此方法在python2中没有,可在python3中使用),下面将对这些进行记录.

    subprocess模块的便利函数

    1)call

    call 函数的定义如下:

    subprocess.call([args,*,stdin=True,stdout=None,stderr=None,shell=False])

    call函数将运行由args参数指定的命令直到命令结束。call函数的返回值是命令的退出状态码,可以通过退出状态码判断命令是否执行成功,例:

    >>> import subprocess
    >>> subprocess.call(['ls','-l'])
    total 24
    -rw-r--r-- 1 root root  783 Feb 20 22:11 find_files.py
    -rwxr-xr-x 1 root root  411 Feb 20 22:20 oswalk.py.bak
    -rw-r--r-- 1 root root   12 Feb 21 19:18 read.txt
    drwxr-xr-x 2 root root 4096 Feb 20 21:06 t1
    -rwxr-xr-x 1 root root  166 Feb 21 19:30 tarfile.py
    -rw-r--r-- 1 root root  271 Feb 21 19:30 tarfile.pyc
    0
    >>> subprocess.call('exit 1',shell=True)
    1
    
    #call函数执行的外部命令以一个字符串列表的形式进行传递,如果设置了shell为True,则可以使用一个字符串命令,而不是一个字符串列表来运行子进程。如果设置了shell为True,
    Python将先运行一个shell,在用这个shell来解释整个字符串
      >>> subprocess.call('ls -l',shell=True)   #设置shell为True,可以直接将命令写在一个字符串里
      total 24
      -rw-r--r-- 1 root root 783 Feb 20 22:11 find_files.py
      -rwxr-xr-x 1 root root 411 Feb 20 22:20 oswalk.py.bak
      -rw-r--r-- 1 root root 12 Feb 21 19:18 read.txt
      drwxr-xr-x 2 root root 4096 Feb 20 21:06 t1
      -rwxr-xr-x 1 root root 166 Feb 21 19:30 tarfile.py
      -rw-r--r-- 1 root root 271 Feb 21 19:30 tarfile.pyc
      0

    获取执行结果的返回码

    >>> import subprocess
    >>> retcode = subprocess.call(["ls", "-l"])   //此命令会在当前终端输出查询结果,并把命令执行返回值赋值给retcode,此变量可自定义,而subprocess_checkout命令含有一个默认的返回值为returncode,可通过根据此值判断命令是否执行成功
    >>> print retcode      //打印命令执行的返回结果即为命令的返回值
    0

    2)check_call

      check_call函数的作用与call函数类似,区别在于异常情况下返回的形式不同。对于call函数,我们通过捕获call命令的返回值判断命令是否执行成功,如果成功返回0,否则返回非0。对于check_call函数,如果执行成功,返回0,如果执行失败,跑出subprocess.CallProcessError异常,例:

    >>> ret = subprocess.check_call(['ls','-l'])
    total 24
    -rw-r--r-- 1 root root  783 Feb 20 22:11 find_files.py
    -rwxr-xr-x 1 root root  411 Feb 20 22:20 oswalk.py.bak
    -rw-r--r-- 1 root root   12 Feb 21 19:18 read.txt
    drwxr-xr-x 2 root root 4096 Feb 20 21:06 t1
    -rwxr-xr-x 1 root root  166 Feb 21 19:30 tarfile.py
    -rw-r--r-- 1 root root  271 Feb 21 19:30 tarfile.pyc
    >>> ret             #命令执行的返回结果即为执行的结果,为0则执行成功,执行失败则直接报错
    0
    >>> subprocess.check_call('exit 1',shell=True) Traceback (most recent call last): File "<stdin>", line 1, in <module> File "/usr/lib64/python2.7/subprocess.py", line 542, in check_call raise CalledProcessError(retcode, cmd) subprocess.CalledProcessError: Command 'exit 1' returned non-zero exit status 1

    3)run       python3中使用

    >>> ret =subprocess.run('ls -l /root',shell=True)
    total 137668
    -rw-r--r-- 1 root root      2476 Apr 12 21:44 17_install_redis.sh
    -rw-r--r-- 1 root root  18471766 Jun 24 16:11 access-settlecenter.huoli.local-http.log
    -rw------- 1 root root 120489984 Mar 27 15:16 consul.tar
    drwxr-xr-x 2 root root      4096 Sep 12 18:18 devops
    drwxrwxr-x 6 root root      4096 May 16  2019 redis-5.0.5
    -rw-r--r-- 1 root root   1975750 Jun  8  2020 redis-5.0.5.tar.gz
    -rw-r--r-- 1 root root       105 Sep  5 16:21 sys_stdin.py
    -rw-r--r-- 1 root root       159 Apr 15 15:31 sys_test.py
    drwxr-xr-x 2 root root      4096 Aug  2 16:37 tablesql
    -rw-r--r-- 1 root root       187 Sep  5 16:03 test.py
    >>> ret
    CompletedProcess(args='ls -l /root', returncode=0) 
    >>> type(ret)                  #命令执行的返回结果为一个对象
    <class 'subprocess.CompletedProcess'>
    >>> ret.returncode      #对象.returncode为命令执行结果
    0

      以上不论是subprocess.call,subprocess.check_call还是subprocess.run方法,都会将命令的执行结果输出在终端,这种返回结果并不是我们想要的到的,一般会对命令的结果进行进一步的处理,或者将命令的输出打印到日志文件中,此时我们就是使用到subprocess.check_output()方法。

    4) check_output

    [root@config test]# cat check_output.py
    #!/usr/bin/python
    from __future__ import print_function
    import subprocess
    
    output=subprocess.check_output(['df','-h'])
    print(output)
    lines=output.split('
    ')
    for line in lines:
        if line:
            print(line.split()[-2])
    [root@config test]# python check_output.py
    Filesystem      Size  Used Avail Use% Mounted on
    devtmpfs        486M     0  486M   0% /dev
    tmpfs           496M     0  496M   0% /dev/shm
    tmpfs           496M   57M  439M  12% /run
    tmpfs           496M     0  496M   0% /sys/fs/cgroup
    /dev/vda1        40G  8.2G   30G  22% /
    tmpfs           100M     0  100M   0% /run/user/0
    overlay          40G  8.2G   30G  22% /var/lib/docker/overlay2/abd499dd2c76192670d51ca193ae471e7c31b839b4a5da581a0ee8fb2fb03f36/merged
    shm              64M     0   64M   0% /var/lib/docker/containers/f336cd4eeaa20c0b3ae42ce96368abfb8d6263ad443e11b06511be9674ad176b/mounts/shm
    
    Mounted
    0%
    0%
    12%
    0%
    22%
    0%
    22%
    0%

        check_output函数通过返回值返回命令的执行结果,显然无法像call函数一样通过返回退出状态码表示异常情况。因此,check_output函数通过抛出一个subprocess.CalledPorcessError异常来表示命令的异常来表示命令执行出错,例:

    try:
        output = subprocess.check_output(['cmd','arg1','arg2'])     //此次output为命令执行的结果存在此变量中,print(output)即为命令的输出结果,output.returncode则为命令执行返回值
    except subprocess.CalledProcessError as e:
        output = e.output
        code = e.returncode
    

    subprocess模块的Popen类

      subprocess模块提供的便利函数都是对Popen类的封装,当便利函数无法满足业务的需求时,也可以直接使用Popen类。Popen类更具有灵活性,通过它能处理更多复杂的情况。Popen类的构造函数如下:

    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)

      Popen的基本使用方式与上一小节中介绍的便利函数类似。在Linux系统中,当shell设置为True时,shell默认使用/bin/sh。args是需要执行的命令,可以是一个命令字符串,也可以是一个字符串列表。

      Popen对象创建后,子进程便会运行。Popen类提供了若干方法来控制子进程的运行,包括:

    poll(): 检查进程是否终止,如果终止返回 returncode,否则返回 None。
    wait(timeout): 等待子进程终止。
    communicate(input,timeout): 和子进程交互,发送和读取数据。
    send_signal(singnal): 发送信号到子进程 。
    terminate(): 停止子进程,也就是发送SIGTERM信号到子进程。
    kill(): 杀死子进程。发送 SIGKILL 信号到子进程。

      其中communicate函数可以与子进程进行交互,包括输入数据,获取子命令的标准输出和错误输出。下面的函数对Popen执行shell命令进行封装,封装以后,只需要将要执行的shell命令传递给函数即可。当命令执行成功时,将返回命令的退出状态码和标准输出,当命令执行失败时,将返回退出状态码和错误输出。

    import subprocess
    import os
    
    def execute_cmd(cmd):
        p = subprocess.Popen(cmd,
                            shell=True,
                            cwd=path   //切换工作目录
                            stdin=subprocess.PIPE,
                            stdout=subprocess.PIPE,
                            stderr=subprocess.PIPE)
        stdout,stderr = p.communicate()
        if p.returnmode != 0:
            return p.returnmode stderr
        return p.returnmode stdout

      通过Python标准库的subprocess模块,可以运行外部程序,极大的拓展了Python的功能。在日常运维工作中,我们可以使用subprocess在python中执行复杂的linux命令。

  • 相关阅读:
    PHP正则表达式概念
    PHP函数
    PHP基础知识总
    PHP运算符知识点
    PHP基础知识1
    学习JavaScript时的三部分
    怎么面向对象编程呢?
    封装、继承、多态
    JS面向对象
    作业day01
  • 原文地址:https://www.cnblogs.com/wushaoyu/p/15259529.html
Copyright © 2011-2022 走看看