Python之subprocess模块

Zss 发表于:

subprocess模块的出现是用来替代OS模块中的system()和popen()方法的,官方推荐的是只用subprocess模块来执行系统命令,subprocess是Python 2.4中新增的一个模块,它允许你生成新的进程,连接到它们的 input/output/error 管道,并获取它们的返回(状态)码。这个模块的目的在于替换几个旧的模块和方法

早期的Python版本中,我们主要是通过os.system()、os.popen().read()等函数来执行命令行指令的,另外还有一个很少使用的commands模块

subprocess的目的就是启动一个新的进程并且与之通信

1.subprocess.call()

执行指定的命令,返回命令执行状态,其功能类似于os.system(cmd)。
#coding:utf-8
import subprocess

cmd = 'ping 192.168.16.1 -n 1'
result = subprocess.call(cmd,shell=True)
print(result)
当命令正常执行输出:结果和0
call()返回一个执行结果的状态码

若cmd为错误的命令
cmd = 'ping 192.168.16.1 -n 1'
输出为:
错误的参数 ss。
1

#!/usr/bin/python2.7
import subprocess
result = subprocess.call('lssdawds /',shell=True)
print result
在liunx中当我输入错误的命令时为什么返回的值是127呢?而不是1呢?当命令正确都返回的为0

2.subprocess.check_output()

Python 2.7中新增的的函数。执行指定的命令,如果执行状态码为0则返回命令执行结果,否则抛出异常。意为:命令成功执行就返回结果失败则报错

#coding:utf-8
import subprocess,os,sys

cmd = 'ping 192.168.16.1 -n 1'
#os.system(cmd)
result = subprocess.check_output(cmd).decode('gbk')
print result
输出:正在 Ping 192.168.16.1 具有 32 字节的数据:
来自 192.168.16.1 的回复: 字节=32 时间<1ms TTL=255192.168.16.1 的 Ping 统计信息:
数据包: 已发送 = 1,已接收 = 1,丢失 = 0 (0% 丢失),
往返行程的估计时间(以毫秒为单位):
最短 = 0ms,最长 = 0ms,平均 = 0ms

cmd = 'ping 192.168.16.1 ss-n 1'
输出为:
subprocess.CalledProcessError: Command 'ping 192.168.16.1 ss-n 1' returned non-zero exit status 1

3.subprocess.Popen()

函数 描述
subprocess.run() Python 3.5中新增的函数。执行指定的命令,等待命令执行完成后返回一个包含执行结果的CompletedProcess类的实例。
subprocess.call() 执行指定的命令,返回命令执行状态,其功能类似于os.system(cmd)。
subprocess.check_call() Python 2.5中新增的函数。 执行指定的命令,如果执行成功则返回状态码,否则抛出异常。其功能等价于subprocess.run(…, check=True)。
subprocess.check_output() Python 2.7中新增的的函数。执行指定的命令,如果执行状态码为0则返回命令执行结果,否则抛出异常。
subprocess.getoutput(cmd) Python3.4才支持winP,接收字符串格式的命令,执行命令并返回执行结果,其功能类似于os.popen(cmd).read()和commands.getoutput(cmd)。
subprocess.getstatusoutput(cmd) Python3.4才支持win,执行cmd命令,返回一个元组(命令执行状态, 命令执行结果输出),其功能类似于commands.getstatusoutput()。

说明:

  1. 在Python 3.5之后的版本中,官方文档中提倡通过subprocess.run()函数替代其他函数来使用subproccess模块的功能;
  2. 在Python 3.5之前的版本中,我们可以通过subprocess.call(),subprocess.getoutput()等上面列出的其他函数来使用subprocess模块的功能;
  3. subprocess.run()、subprocess.call()、subprocess.check_call()和subprocess.check_output()都是通过对subprocess.Popen的封装来实现的高级函数,因此如果我们需要更复杂功能时,可以通过subprocess.Popen来完成。
  4. subprocess.getoutput()和subprocess.getstatusoutput()函数是来自Python 2.x的commands模块的两个遗留函数。它们隐式的调用系统shell,并且不保证其他函数所具有的安全性和异常处理的一致性。另外,它们从Python 3.3.4开始才支持Windows平台。

函数参数列表:

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

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

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

subprocess.check_output(args, *, stdin=None, stderr=None, shell=False, universal_newlines=False, timeout=None)

subprocess.getstatusoutput(cmd)

subprocess.getoutput(cmd)

参数说明:

  • args: 要执行的shell命令,默认应该是一个字符串序列,如[‘df’, ‘-Th’]或(‘df’, ‘-Th’),也可以是一个字符串,如’df -Th’,但是此时需要把shell参数的值置为True。
  • shell: 如果shell为True,那么指定的命令将通过shell执行。如果我们需要访问某些shell的特性,如管道、文件名通配符、环境变量扩展功能,这将是非常有用的。当然,python本身也提供了许多类似shell的特性的实现,如glob、fnmatch、os.walk()、os.path.expandvars()、os.expanduser()和shutil等。
  • check: 如果check参数的值是True,且执行命令的进程以非0状态码退出,则会抛出一个CalledProcessError的异常,且该异常对象会包含 参数、退出状态码、以及stdout和stderr(如果它们有被捕获的话)。
  • stdout, stderr:
  • run()函数默认不会捕获命令执行结果的正常输出和错误输出,如果我们向获取这些内容需要传递subprocess.PIPE,然后可以通过返回的CompletedProcess类实例的stdout和stderr属性或捕获相应的内容;
  • call()和check_call()函数返回的是命令执行的状态码,而不是CompletedProcess类实例,所以对于它们而言,stdout和stderr不适合赋值为subprocess.PIPE;
  • check_output()函数默认就会返回命令执行结果,所以不用设置stdout的值,如果我们希望在结果中捕获错误信息,可以执行stderr=subprocess.STDOUT。
  • input: 该参数是传递给Popen.communicate(),通常该参数的值必须是一个字节序列,如果universal_newlines=True,则其值应该是一个字符串。
  • universal_newlines: 该参数影响的是输入与输出的数据格式,比如它的值默认为False,此时stdout和stderr的输出是字节序列;当该参数的值设置为True时,stdout和stderr的输出是字符串。

实例

subprocess.run()

>>> subprocess.run(["ls", "-l"])  # doesn't capture output
CompletedProcess(args=['ls', '-l'], returncode=0)

>>> subprocess.run("exit 1", shell=True, check=True)
Traceback (most recent call last):
  ...
subprocess.CalledProcessError: Command 'exit 1' returned non-zero exit status 1

>>> subprocess.run(["ls", "-l", "/dev/null"], stdout=subprocess.PIPE)
CompletedProcess(args=['ls', '-l', '/dev/null'], returncode=0,
stdout=b'crw-rw-rw- 1 root root 1, 3 Jan 23 16:23 /dev/null\n')

subprocess.call()

>>> subprocess.call(['ls',  '-l'])
总用量 160
drwxr-xr-x  2 wader wader   4096 127  2015 公共的
drwxr-xr-x  2 wader wader   4096 127  2015 模板
drwxr-xr-x  2 wader wader   4096 127  2015 视频
drwxr-xr-x  2 wader wader   4096 127  2015 图片
drwxr-xr-x  2 wader wader   4096 127  2015 文档
drwxr-xr-x  2 wader wader   4096  413  2016 下载
drwxr-xr-x  2 wader wader   4096 127  2015 音乐
drwxr-xr-x  7 wader wader   4096  526  2016 桌面
0
>>> subprocess.call('ls -l', shell=True)
总用量 160
drwxr-xr-x  2 wader wader   4096 127  2015 公共的
drwxr-xr-x  2 wader wader   4096 127  2015 模板
drwxr-xr-x  2 wader wader   4096 127  2015 视频
drwxr-xr-x  2 wader wader   4096 127  2015 图片
drwxr-xr-x  2 wader wader   4096 127  2015 文档
drwxr-xr-x  2 wader wader   4096  413  2016 下载
drwxr-xr-x  2 wader wader   4096 127  2015 音乐
drwxr-xr-x  7 wader wader   4096  526  2016 桌面
0
>>> subprocess.call(['ls',  '-l'], stdout=subprocess.DEVNULL)
0
>>> subprocess.call(['ls',  '-l', '/test'])
ls: 无法访问/test: 没有那个文件或目录
2
suprocess.check_call()
>>> subprocess.check_call(['ls',  '-l'])
总用量 160
drwxr-xr-x  2 wader wader   4096 127  2015 公共的
drwxr-xr-x  2 wader wader   4096 127  2015 模板
drwxr-xr-x  2 wader wader   4096 127  2015 视频
drwxr-xr-x  2 wader wader   4096 127  2015 图片
drwxr-xr-x  2 wader wader   4096 127  2015 文档
drwxr-xr-x  2 wader wader   4096  413  2016 下载
drwxr-xr-x  2 wader wader   4096 127  2015 音乐
drwxr-xr-x  7 wader wader   4096  526  2016 桌面
0
>>> subprocess.check_call('ls -l', shell=True)
总用量 160
drwxr-xr-x  2 wader wader   4096 127  2015 公共的
drwxr-xr-x  2 wader wader   4096 127  2015 模板
drwxr-xr-x  2 wader wader   4096 127  2015 视频
drwxr-xr-x  2 wader wader   4096 127  2015 图片
drwxr-xr-x  2 wader wader   4096 127  2015 文档
drwxr-xr-x  2 wader wader   4096  413  2016 下载
drwxr-xr-x  2 wader wader   4096 127  2015 音乐
drwxr-xr-x  7 wader wader   4096  526  2016 桌面
0
>>> subprocess.check_call('ls -l /test', shell=True)
ls: 无法访问/test: 没有那个文件或目录
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "/usr/lib/python3.4/subprocess.py", line 557, in check_call
    raise CalledProcessError(retcode, cmd)
subprocess.CalledProcessError: Command 'ls -l /test' returned non-zero exit status 2

sbuprocess.check_output()

>>> ret = subprocess.check_output(['ls',  '-l'])
>>> print(ret)
b' \xe5\x85\xac\xe5\x85\xb1\xe7\x9a\x84\ndrwxr-xr-x  2 wader wader   4096 12\xe6\x9c\x88  7  2015 \xe6\xa8\xa1\xe6\x9d\xbf\ndrwxr-xr-x  2 wader wader   4096 12\xe6\x9c\x88  7  2015 \xe8\xa7\x86\xe9\xa2\x91\ndrwxr-xr-x  2 wader wader   4096 12\xe6\x9c\x88  7  2015 \xe5\x9b\xbe\xe7\x89\x87\ndrwxr-xr-x  2 wader wader   4096 12\xe6\x9c\x88  7  2015 \xe6\x96\x87\xe6\xa1\xa3\ndrwxr-xr-x  2 wader wader   4096  4\xe6\x9c\x88 13  2016 \xe4\xb8\x8b\xe8\xbd\xbd\ndrwxr-xr-x  2 wader wader   4096 12\xe6\x9c\x88  7  2015 \xe9\x9f\xb3\xe4\xb9\x90\ndrwxr-xr-x  7 wader wader   4096  5\xe6\x9c\x88 26  2016 \xe6\xa1\x8c\xe9\x9d\xa2\n'
>>> ret = subprocess.check_output(['ls',  '-l'], universal_newlines=True)
>>> print(ret)
总用量 160
drwxr-xr-x  2 wader wader   4096 127  2015 公共的
drwxr-xr-x  2 wader wader   4096 127  2015 模板
drwxr-xr-x  2 wader wader   4096 127  2015 视频
drwxr-xr-x  2 wader wader   4096 127  2015 图片
drwxr-xr-x  2 wader wader   4096 127  2015 文档
drwxr-xr-x  2 wader wader   4096  413  2016 下载
drwxr-xr-x  2 wader wader   4096 127  2015 音乐
drwxr-xr-x  7 wader wader   4096  526  2016 桌面

subprocess.getoutput()与subprocess.getstatusoutput()

>>> ret = subprocess.getoutput('ls -l')
>>> print(ret)
总用量 160
drwxr-xr-x  2 wader wader   4096 127  2015 公共的
drwxr-xr-x  2 wader wader   4096 127  2015 模板
drwxr-xr-x  2 wader wader   4096 127  2015 视频
drwxr-xr-x  2 wader wader   4096 127  2015 图片
drwxr-xr-x  2 wader wader   4096 127  2015 文档
drwxr-xr-x  2 wader wader   4096  413  2016 下载
drwxr-xr-x  2 wader wader   4096 127  2015 音乐
drwxr-xr-x  7 wader wader   4096  526  2016 桌面
>>> retcode, output = subprocess.getstatusoutput('ls -l')
>>> print(retcode)
0
>>> print(output)
总用量 160
drwxr-xr-x  2 wader wader   4096 127  2015 公共的
drwxr-xr-x  2 wader wader   4096 127  2015 模板
drwxr-xr-x  2 wader wader   4096 127  2015 视频
drwxr-xr-x  2 wader wader   4096 127  2015 图片
drwxr-xr-x  2 wader wader   4096 127  2015 文档
drwxr-xr-x  2 wader wader   4096  413  2016 下载
drwxr-xr-x  2 wader wader   4096 127  2015 音乐
drwxr-xr-x  7 wader wader   4096  526  2016 桌面
>>> retcode, output = subprocess.getstatusoutput('ls -l /test')
>>> print(retcode)
2
>>> print(output)
ls: 无法访问/test: 没有那个文件或目录