四、subprocess远程执行命令模块

一、subprocess模块简介

subprocess模块最早是在python2.4版本中引入的,正如它名字所反映的,这个模块用于创建和管理子进程。它提供了高层次的接口,用来替换os.system(),os.spawn(), os.popen()和commands.*等模块与函数。subprocess其实非常简单,它提供了一个名为Popen的类来启动和设置子进程的参数。由于这个类比较复杂,subprocess还提供了苦干便利函数。这些便利函数都是对Popen这个类的封装,以便工程师能够快速启动一个子进程并获取它们的输出结果。

二、subprocess模块的便利函数

在subprocess模块中启动子进程,最简单的方式就是使用便利函数。当这些便利函数不能满足需求时,再使用底层Popen类。便利函数包括call,check_call与check_output.

  1. call

call 函数的定义如下:

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

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

import subprocess

data = subprocess.call(['ls', '-l'])
print(data)

# run
/usr/local/bin/python3.6 /Users/xcn/PycharmProjects/自动化运维/subprocess模块/便利函数.py
total 8
-rw-r--r--  1 xcn  staff  113 Jun 10 10:46 便利函数.py
0

  1. check_call

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

#!/usr/bin/env python
# -*- coding: utf-8 -*-
import subprocess

data = subprocess.check_call(['ls', '-l'])
print(data)


data1 = subprocess.check_call("exit 1 ",shell=True)


# run

/usr/local/bin/python3.6 /Users/xcn/PycharmProjects/自动化运维/subprocess模块/便利函数.py
total 8
-rw-r--r--  1 xcn  staff  173 Jun 10 10:51 便利函数.py
0
Traceback (most recent call last):
  File "/Users/xcn/PycharmProjects/自动化运维/subprocess模块/便利函数.py", line 9, in <module>
    data1 = subprocess.check_call("exit 1 ",shell=True)
  File "/Library/Frameworks/Python.framework/Versions/3.6/lib/python3.6/subprocess.py", line 291, in check_call
    raise CalledProcessError(retcode, cmd)
subprocess.CalledProcessError: Command 'exit 1 ' returned non-zero exit status 1.

  1. check_output

从上面的输出结果可以看到,call和check_call 函数直接将命令的输出结果输出到命令行终端,这种返回结果的形式很有课程不是你想要的。在实际工作过程中,一般会对获取命令的结果进行进一步的处理,或者将命令的输出打印到日志文件中。

import subprocess

output = subprocess.check_output(['df','-h'])
lines = output.split('/n')
for line in lines[1:-1]:
    print(line.split()[-2])

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

#!/usr/bin/env python
# -*- coding: utf-8 -*-
import subprocess

try:
    output = subprocess.check_output(['cmd','arg1','arg2'])
except subprocess.CalledProcessError as e:
    output = e.output
    code = e.returncode
    
    
# 默认情况下,check_output命令只会捕获命令的标准输出。如果想捕获命令的错误输出,需要将错误输出重定向到标准输出。

output = subprocess.check_output(['cmd','arg1','arg2'],stderr=subprocess.STDOUT)

三、subprocess模块的Popen类

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

class 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,creationflafe=0)      

在Unix系统中,当shell设置为True时,shell默认使用/bin/sh。args是需要执行的命令,可以是一个命令字符串,也可以是一个字符串列表。

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

  • wait: 等待子进程结束

  • poll: 检查子进程状态

  • kill: 给子进程发送SIGKILL信号终止子进程

  • send_signal: 向子进程发送信号

  • terminate: 给子进程发送SIGTERM信号终于子进程

  • communicate: 与子进程交互

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

#!/usr/bin/env python
# -*- coding: utf-8 -*-
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

通过Python标准库的subprocess模块,可以运行外部程序。这极大地拓展了Python的功能。例如,可以使用subprocess在Python中执行复杂的Linux命令。

posted @ 2018-06-10 11:30  云原生运维社区  阅读(1708)  评论(0编辑  收藏  举报