四、subprocess远程执行命令模块
一、subprocess模块简介
subprocess模块最早是在python2.4版本中引入的,正如它名字所反映的,这个模块用于创建和管理子进程。它提供了高层次的接口,用来替换os.system(),os.spawn(), os.popen()和commands.*等模块与函数。subprocess其实非常简单,它提供了一个名为Popen的类来启动和设置子进程的参数。由于这个类比较复杂,subprocess还提供了苦干便利函数。这些便利函数都是对Popen这个类的封装,以便工程师能够快速启动一个子进程并获取它们的输出结果。
二、subprocess模块的便利函数
在subprocess模块中启动子进程,最简单的方式就是使用便利函数。当这些便利函数不能满足需求时,再使用底层Popen类。便利函数包括call,check_call与check_output.
- 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
- 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.
- 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命令。