[TOC]

## 模块说明

subprocess是Python 2.4中新增的一个模块提供了一个更高级的接口。用于替换和系统交互的os.system() , os.spawnv()等.

在Python 3.5之后,官方提倡通过subprocess.run()函数替代其他函数来使用subproccess模块的功能;

在Python 3.5之前的版本中,我们可以通过subprocess的call()、getoutput()等函数来使用subprocess模块的功能;

run()、call()、check_call()和check_output()都是通过对Popen的封装来实现的高级函数,因此如果我们需要更复杂功能时,可以通过subprocess.Popen来完成。

### 常用函数语法

* run函数

3.5中新增。执行指定的命令,等待命令执行完成后返回一个包含执行结果的CompletedProcess类的实例。

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

* call函数

执行指定的命令,返回命令执行状态,其功能类似于os.system(cmd)

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

* check_call函数

2.5中新增。 执行指定的命令,如果执行成功则返回状态码,否则抛出异常。等价于`subprocess.run(..., check=True)`

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

* check_output函数

2.7中新增。执行指定的命令,如果执行状态码为0则返回命令执行结果,否则抛出异常。

```
subprocess.check_output(args, *, stdin=None, stderr=None, shell=False, universal_newlines=False, timeout=None)
```
* getstatusoutput、getoutput函数
```
subprocess.getstatusoutput(cmd)
subprocess.getoutput(cmd)
```
* Popen方法[底层方法]
```
subprocess.Popen()
```

### 参数说明

* args:

要执行的shell命令,默认是一个字符串序列,如['df', '-Th']或('df', '-Th'),也可以是一个字符串,如'df -Th',但需要shell参数的值为True。

* shell:

如果shell为True,那么指定的命令将通过shell执行。在命令中有管道、通配符、环境变量等时非常有用。

* check:

如果check参数的值是True,且执行命令的进程以非0状态码退出,则会抛出一个CalledProcessError的异常,包含 参数、退出状态码、以及stdout和stderr

* stdout, stderr:

run()函数默认不会捕获命令执行结果的正常输出和错误输出而直接返回到屏幕,如果要捕获需要通过`stdout=subprocess.PIPE`来捕获,然后用CompletedProcess类实例的stdout和stderr属性来输出的内容

>call()和check_call()函数返回的是命令执行的状态码,对于它们而言,stdout和stderr不适合赋值为subprocess.PIPE;

check_output()函数默认就会返回命令执行结果,所以只需在捕获错误信息时,执行stderr=subprocess.STDOUT

* input:

该参数是传递给Popen.communicate(),通常该参数的值必须是一个字节列表,如果universal_newlines=True,则其值应该是一个字符串。

* universal_newlines:

该参数影响的是输入与输出的数据格式,比如它的值默认为False,此时stdout和stderr的输出是字节序列;当该参数的值设置为True时,stdout和stderr的输出是字符串。

### subprocess.CompletedProcess类介绍

run()函数是Python3.5中新增的一个高级函数,其返回值是一个CompletedPorcess类的实例,completedPorcess类也是Python 3.5中才存在的。

它表示的是一个已结束进程的状态信息,它所包含的属性如下:

* args:

用于加载该进程的参数,这可能是一个列表或一个字符串

* returncode:

子进程的退出状态码。0成功,非0失败;负值-N表示这个子进程被信号N终止了

* stdout:

从子进程捕获的stdout。这通常是一个字节序列

* stderr:

从子进程捕获的stderr,字节列表。如果stderr未被捕获的话,为None

* check_returncode():

如果returncode是一个非0值,则该方法会抛出一个CalledProcessError异常。

## `run()`方法举例

### 1.常见写法

默认run方法是将命令结果直接输出,而不存储,自身只存储`CompletedProcess`方法

```
>>> subprocess.run(['free','-h'])
>>> subprocess.run('free -h',shell=True)
>>> a=subprocess.run(['free','-h'],shell=True)
total used free shared buff/cache available
Mem: 2017280 1053132 231080 6772 733068 748920
Swap: 998396 12544 985852
>>> a
CompletedProcess(args=['free', '-h'], returncode=0)
```

### 获取返回结果

如果想要捕获命令执行的结果和错误供其他时候调用,需要通过python的管道捕获,如下

* stdout=subprocess.PIPE 命令执行成功返回的内容
* stderr=subprocess.PIPE 命令执行错误返回的错误内容
```
>>> a=subprocess.run(['free','-h'],stdout=subprocess.PIPE,stderr=subprocess.PIPE)
>>> a.stdout.decode() # 如果命令执行正确,此方法就读出程序结果
>>> a.stderr.decode() # 如果命令执行错误,此方法就读出报错信息
```

>因为执行一条命令就会打开一个进程,进程间数据不能通信,所以需要先将结果赋予stdout、stderr的,再传给程序

### 遇到错误停止

subprocess.run()方法执行命令时,如果命令是错的,程序不会报错而继续运行,如果要命令错的时候程序报错停止运行的话,可以加个check参数

```
>>> subprocess.run('free -sh',shell=True,check=True)
>>> a=subprocess.run(['free','-h'],stdout=subprocess.PIPE,stderr=subprocess.PIPE,check=True)
```

>check参数设置为True的时候就会检查命令是否是错的

## 除popen外其他方法
### call方法
call方法会将结果直接输出,自身自获取命令执行状态,0 or 非0
```
>>> b=subprocess.call('ls /dev/null',shell=True)
/dev/null
>>> b
0
```
### check_call方法
check_call方法是如果命令正常执行就返回状态码0,否则抛异常
```
>>> b=subprocess.check_call('ls /dev/null',shell=True)
/dev/null
>>> b
0
```
### check_output方法
check_output执行命令,如果正常执行则并结果,否则抛出异常
```
>>> subprocess.check_output('ls /dev/null',shell=True)
b'/dev/null\n'
>>> b=subprocess.check_output('ls /dev/null',shell=True)
>>> b
b'/dev/null\n'
```

### getoutput和getstatusoutput方法

getoutput和getstatusoutput函数是Python 2.x的commands模块的遗留函数。 隐式的调用系统shell,不保证其他函数所具有的安全性和异常处理的一致性。且3.3.4开始才支持Windows平台。

* getstatusoutput方法

接收字符串格式命令,返回元组形式,第1个元素是执行状态,第2个是命令结果

```
>>> subprocess.getstatusoutput('ls /bin/ls')
(0, '/bin/ls')
```

* getoutput方法

接收字符串格式命令,并返回结果

```
>>> subprocess.getoutput('ls /bin/ls')
'/bin/ls'
```

## `Popen()`方法详解

函数call(), check_call() 和 check_output() 都是Popen类的包装器。直接使用Popen会对如何运行命令以及如何处理其输入输出有更多控制。如通过为stdin, stdout和stderr传递不同的参数。

### 常用参数:

* args:

shell命令,可以是字符串或者序列类型(如:list,元组)

* stdin, stdout, stderr:

分别表示程序的标准输入,标准输出及标准错误

* preexec_fn:

只在Unix平台下有效,用于指定一个可执行对象,它将在子进程运行之前被调用

* shell:

与其他方法中用法相同

* cwd:

用于设置子进程的当前目录

* env:

用于指定子进程的环境变量。如果env=None,则默认从父进程继承环境变量

universal_newlines:不同系统的的换行符不同,当该参数设定为true时,则表示使用`\n`作为换行符

### Popen的方法

Popen和run区别是,run会在当前界面等待命令执行完成,Popen执行后后立刻返回一个对象,而不等命令执行结果。

```
a=subprocess.run('sleep 10',shell=True,stdout=subprocess.PIPE)
a=subprocess.Popen('sleep 10',shell=True,stdout=subprocess.PIPE)`
```

**Popen返回的对象有以下方法**

* Popen.poll()

检查子进程是否已终止,设置并返回returncode属性

* Popen.wait (timeout=None)

等待子进程终止,设置并返回returncode属性

* Popen.communicate()

与启动的子进程交互,发送数据到stdin,并从stdout接收输出,然后等待任务结束

* Popen.pid ()

返回子进程ID

* Popen.returncode ()

返回子进程的状态码.

* Popen.terminate()

停止子进程

* Popen.kill()

杀死子进程

* Popen.send_signal()

向子进程发送信号

* Popen.args ()

传递给Popen的参数,可以是列表 或者 字符串

* Popen.stdin()/stdout()/stderr()

如果stdin/stdout/stderr 参数是PIPE,返回可写流对象,如果指定encoding等参数为True,怎是文本流,否则字节流,如果stdin的参数不是PIPE,返回None

### 操作举例

* 查看pid和返回值等

```python
>>> aa=subprocess.Popen('for i in `seq 5`;do echo "$i";done',stdout=subprocess.PIPE,shell=True)
>>> aa.pid
44695
>>> aa.poll()
0
>>> aa.communicate()
(b'1\n2\n3\n4\n5\n', None)
```

* 输出结果定向到标准输出供其他程序使用

```python
>>> aa=subprocess.Popen('cat /etc/passwd',stdout=subprocess.PIPE,shell=True)
>>> subprocess.Popen('grep root',stdin=aa.stdout,shell=True)
root:x:0:0:root:/root:/bin/bash
```