• subprocess


    使用Python进行Linux系统管理与运维总是免不了在Python代码中执行shell命令、启动子进程,并捕获命令的输出和退出状态。
    而subprocess模块就可以实现, 它最早是在python2.4版本中引入中。

    call

    call函数的返回值是命令的退出状态码,工程师可以通过退出状态码判命令是否执行成功, 成功返回0,否则返回非0

    call函数执行的外部命令以一个字符串列表的形式进行传递

    In [31]: status_code = subprocess.call(['ls', '-l'])
    total 17700
    drwxr-xr-x  9 nginx nginx     4096 Nov 10 00:10 nginx-1.12.2
    -rw-r--r--  1 root  root    981687 Dec 22  2017 nginx-1.12.2.tar.gz
    drwxr-xr-x 14 nginx nginx     4096 Nov 10 00:02 zabbix-3.4.4
    -rw-r--r--  1 root  root  17132537 Dec 25  2017 zabbix-3.4.4.tar.gz
    
    In [32]: status_code
    Out[32]: 0
    subprocess.call(['ls', '-l'])

    如果设置了shell为True,则可以使用一个字符串命令,python将先运行一个shell,在用这个shell来解释整个字符串

    In [34]: status_code = subprocess.call('ls -l', shell=True)
    total 17700
    drwxr-xr-x  9 nginx nginx     4096 Nov 10 00:10 nginx-1.12.2
    -rw-r--r--  1 root  root    981687 Dec 22  2017 nginx-1.12.2.tar.gz
    drwxr-xr-x 14 nginx nginx     4096 Nov 10 00:02 zabbix-3.4.4
    -rw-r--r--  1 root  root  17132537 Dec 25  2017 zabbix-3.4.4.tar.gz
    
    In [35]: status_code
    Out[35]: 0
    subprocess.call('ls -l', shell=True)

    模拟执行失败

    In [39]: status_code = subprocess.call('exit 1', shell=True)
    
    In [40]: status_code
    Out[40]: 1
    subprocess.call('exit 1', shell=True)

    check_call

     check_call函数的作用与call函数类似,区别在于异常情况下返回的形式不同,对于check_call函数,如果命令执行成功,返回0,如果执行失败,抛出suprocess.CalledProcessError异常

    In [41]: status_code = subprocess.check_call('exit 1', shell=True)
    ---------------------------------------------------------------------------
    CalledProcessError                        Traceback (most recent call last)
    <ipython-input-41-7ec365b00bf2> in <module>()
    ----> 1 status_code = subprocess.check_call('exit 1', shell=True)
    
    /usr/lib64/python2.7/subprocess.pyc in check_call(*popenargs, **kwargs)
        540         if cmd is None:
        541             cmd = popenargs[0]
    --> 542         raise CalledProcessError(retcode, cmd)
        543     return 0
        544 
    
    CalledProcessError: Command 'exit 1' returned non-zero exit status 1
    subprocess.check_call('exit 1', shell=True)

    check_output

    call和check_call函数直接将命令的输出结果输出到命令行终端。在实际工作中,一般会对获取的命令结果进行进一步的处理,或者将命令的输出打印到日志文件中。

    In [42]: output = subprocess.check_output(['df', '-h'])
    
    In [43]: print(output)
    Filesystem      Size  Used Avail Use% Mounted on
    /dev/sda1        20G  2.3G   18G  12% /
    devtmpfs        904M     0  904M   0% /dev
    tmpfs           913M  4.0K  913M   1% /dev/shm
    tmpfs           913M  9.7M  903M   2% /run
    tmpfs           913M     0  913M   0% /sys/fs/cgroup
    tmpfs           183M     0  183M   0% /run/user/0
    
    
    In [44]: lines = output.split('
    ')
    
    In [46]: lines
    Out[46]: 
    ['Filesystem      Size  Used Avail Use% Mounted on',
     '/dev/sda1        20G  2.3G   18G  12% /',
     'devtmpfs        904M     0  904M   0% /dev',
     'tmpfs           913M  4.0K  913M   1% /dev/shm',
     'tmpfs           913M  9.7M  903M   2% /run',
     'tmpfs           913M     0  913M   0% /sys/fs/cgroup',
     'tmpfs           183M     0  183M   0% /run/user/0',
     '']
    
     In [47]: for line in lines[1:-1]:
        ...:     if line:
        ...:         print(line.split()[-2])
        ...:         
    12%
    0%
    1%
    2%
    0%
    0%
    View Code

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

    try:
        output = subprocess.check_output(['cmd', 'arg1', 'arg2'])
    except subprocess.CalledProcessError as e:
        output = e.output
        code = e.returncode

    默认情况下,check_ouput命令只会捕获命令的标准输出。如果想捕获命令的错误输出,需要将输出重定向到标准输出。如下所示:

    In [9]: try:
       ...:     subprocess.check_output(['rm', '-f', '/tmp/root.txt'], stderr=subprocess.STDOUT)
       ...: except subprocess.CalledProcessError as e:
       ...:     output = e.output
       ...:     code = e.returncode
       ...:            
    
    In [10]: output
    Out[10]: 'rm: cannot remove xe2x80x98/tmp/root.txtxe2x80x99: Operation not permitted
    '

    Popen类

    当以上便利函数无法满足业务的需求时,也可以直接使用Popen类。Popen类更具有灵活性,能够通过它处理更多复制的情况。

    下面的函数对Popen执行shell命令进行封装,封装以后,只要将需要执行的shell命令传递给该函数即可。当命令执行成功时,将返回命令退出的状态码和标准输出,当命令执行失败时,将返回退出状态码和错误输出

    import sys
    import subprocess
    
    def execute_cmd(cmd):
        p = subprocess.Popen(cmd,
                             shell=True,
                             stdin=subprocess.PIPE,
                             stdout=subprocess.PIPE,
                             stderr=subprocess.PIPE)
        stdout, stderr = p.communicate()
        if p.returncode != 0:
            return p.returncode, stderr
        return p.returncode, stdout
    
    print(execute_cmd(sys.argv[1]))

  • 相关阅读:
    codeforces 1060 B
    codeforces 1060 A
    牛客 国庆七天乐 day1 L
    BZOJ 1087: [SCOI2005]互不侵犯King
    codeforces 792CDivide by Three(两种方法:模拟、动态规划
    codeforces 797C Minimal string
    codeforces 110E Lucky Tree
    codeforces 798D
    2017福建省赛 FZU2272~2283
    Android -- Looper、Handler、MessageQueue等类之间关系的序列图
  • 原文地址:https://www.cnblogs.com/sellsa/p/9939338.html
Copyright © 2020-2023  润新知