python subprocess详解

python subprocess详解

简介:

运行python的时候,我们都是在创建并运行一个进程。像Linux进程那样,一个进程可以fork一个子进程,并让这个子进程exec另外一个程序。在Python中,我们通过标准库中的subprocess包来fork一个子进程,并运行一个外部的程序。
subprocess包中定义有数个创建子进程的函数,这些函数分别以不同的方式创建子进程,所以我们可以根据需要来从中选取一个使用。另外subprocess还提供了一些管理标准流(standard stream)和管道(pipe)的工具,从而在进程间使用文本通信。

subprocess.call()

父进程等待子进程完成
返回退出信息(returncode,相当于Linux exit code)

示例:

>>> a = subprocess.call(['df','-hT'],shell=False)
文件系统       类型      容量  已用  可用 已用% 挂载点
/dev/vda3      xfs        80G  3.6G   77G    5% /
devtmpfs       devtmpfs  7.8G     0  7.8G    0% /dev
tmpfs          tmpfs     7.8G     0  7.8G    0% /dev/shm
tmpfs          tmpfs     7.8G  8.6M  7.8G    1% /run
tmpfs          tmpfs     7.8G     0  7.8G    0% /sys/fs/cgroup
/dev/vda6      xfs       404G  2.2G  402G    1% /data1
/dev/vda2      xfs       497M  128M  370M   26% /boot
tmpfs          tmpfs     1.5G     0  1.5G    0% /run/user/0
>>> print(a)
0    #程序返回的代码值
>>> a = subprocess.call('aaaa',shell=True)
/bin/sh: aaaa: 未找到命令
>>> 

subprocess.check_call()

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

与call方法类似,不同在于如果命令行执行成功,check_call返回返回码0,否则抛出subprocess.CalledProcessError异常
subprocess.CalledProcessError异常包括returncode、cmd、output等属性,其中returncode是子进程的退出码,cmd是子进程的执行命令,output为None。

示例:

>>> import subprocess
>>> a = subprocess.check_call('df -h',shell=True)
文件系统        容量  已用  可用 已用% 挂载点
/dev/vda3        80G  3.6G   77G    5% /
devtmpfs        7.8G     0  7.8G    0% /dev
tmpfs           7.8G     0  7.8G    0% /dev/shm
tmpfs           7.8G  8.6M  7.8G    1% /run
tmpfs           7.8G     0  7.8G    0% /sys/fs/cgroup
/dev/vda6       404G  2.2G  402G    1% /data1
/dev/vda2       497M  128M  370M   26% /boot
tmpfs           1.2G     0  1.2G    0% /run/user/0
>>> print(a)
0
>>> a = subprocess.check_call('aaaa',shell=True)
/bin/sh: aaaa: 未找到命令
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "/usr/local/python3/lib/python3.6/subprocess.py", line 291, in check_call
    raise CalledProcessError(retcode, cmd)
subprocess.CalledProcessError: Command 'aaaa' returned non-zero exit status 127.
>>> 

subprocess.check_output():

用法与上面两个方法类似,区别是,如果当返回值为0时,直接返回输出结果,如果返回值不为0,直接抛出异常

示例:

>>> a = subprocess.check_output(['df','-hT'],shell=False)
>>> print(a)
b'\xe6\x96\x87\xe4\xbb\xb6\xe7\xb3\xbb\xe7\xbb\x9f       \xe7\xb1\xbb\xe5\x9e\x8b      \xe5\xae\xb9\xe9\x87\x8f  \xe5\xb7\xb2\xe7\x94\xa8  \xe5\x8f\xaf\xe7\x94\xa8 \xe5\xb7\xb2\xe7\x94\xa8% \xe6\x8c\x82\xe8\xbd\xbd\xe7\x82\xb9\n/dev/vda3      xfs        80G  3.6G   77G    5% /\ndevtmpfs       devtmpfs  7.8G     0  7.8G    0% /dev\ntmpfs          tmpfs     7.8G     0  7.8G    0% /dev/shm\ntmpfs          tmpfs     7.8G  8.6M  7.8G    1% /run\ntmpfs          tmpfs     7.8G     0  7.8G    0% /sys/fs/cgroup\n/dev/vda6      xfs       404G  2.2G  402G    1% /data1\n/dev/vda2      xfs       497M  128M  370M   26% /boot\ntmpfs          tmpfs     1.5G     0  1.5G    0% /run/user/0\n'
>>> print(str(a.rstrip(),'utf-8'))
文件系统       类型      容量  已用  可用 已用% 挂载点
/dev/vda3      xfs        80G  3.6G   77G    5% /
devtmpfs       devtmpfs  7.8G     0  7.8G    0% /dev
tmpfs          tmpfs     7.8G     0  7.8G    0% /dev/shm
tmpfs          tmpfs     7.8G  8.6M  7.8G    1% /run
tmpfs          tmpfs     7.8G     0  7.8G    0% /sys/fs/cgroup
/dev/vda6      xfs       404G  2.2G  402G    1% /data1
/dev/vda2      xfs       497M  128M  370M   26% /boot
tmpfs          tmpfs     1.5G     0  1.5G    0% /run/user/0
>>> 

subprocess.Popen():

subprocess模块定义了一个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, creationflags=0)

在一些复杂场景中,我们需要将一个进程的执行输出作为另一个进程的输入。在另一些场景中,我们需要先进入到某个输入环境,然后再执行一系列的指令等。这个时候我们就需要使用到suprocess的Popen()方法。该方法有以下参数

参数 作用
args 一般是一个字符串,是要执行的shell命令内容
bufsize 设置缓冲,负数表示系统默认缓冲,0表示无缓冲,正数表示自定义缓冲行数
stdin 程序的标准输入句柄,NONE表示不进行重定向,继承父进程,PIPE表示创建管道
stdout 程序的标准输出句柄,参数意义同上
stderr 程序的标准错误句柄,参数意义同上,特殊,可以设置成STDOUT,表示与标准输出一致
shell 为True时,表示将通过shell来执行
cwd 用来设置当前子进程的目录
env 用于指定子进程的环境变量。如果env=None,则默认从父进程继承环境变量
universal_newlines 不同系统的的换行符不同,当该参数设定为true时,则表示使用\n作为换行符。

Popen方法:

  • 1、Popen.poll():用于检查子进程是否已经结束。设置并返回returncode属性。
  • 2、Popen.wait():等待子进程结束。设置并返回returncode属性。
  • 3、Popen.communicate(input=None):与子进程进行交互。向stdin发送数据,或从stdout和stderr中读取数据。可选参数input指定发送到子进程的参数。Communicate()返回一个元组:(stdoutdata, stderrdata)。注意:如果希望通过进程的stdin向其发送数据,在创建Popen对象的时候,参数stdin必须被设置为PIPE。同样,如果希望从stdout和stderr获取数据,必须将stdout和stderr设置为PIPE。
  • 4、Popen.send_signal(signal):向子进程发送信号。
  • 5、Popen.terminate():停止(stop)子进程。在windows平台下,该方法将调用Windows API TerminateProcess()来结束子进程。
  • 6、Popen.kill():杀死子进程。
  • 7、Popen.stdin:如果在创建Popen对象是,参数stdin被设置为PIPE,Popen.stdin将返回一个文件对象用于策子进程发送指令。否则返回None。
  • 8、Popen.stdout:如果在创建Popen对象是,参数stdout被设置为PIPE,Popen.stdout将返回一个文件对象用于策子进程发送指令。否则返回None。
  • 9、Popen.stderr:如果在创建Popen对象是,参数stdout被设置为PIPE,Popen.stdout将返回一个文件对象用于策子进程发送指令。否则返回None。
  • 10、Popen.pid:获取子进程的进程ID。
  • 11、Popen.returncode:获取进程的返回值。如果进程还没有结束,返回None。
  • 12、subprocess.call(*popenargs, **kwargs):运行命令。该函数将一直等待到子进程运行结束,并返回进程的returncode。文章一开始的例子就演示了call函数。如果子进程不需要进行交互,就可以使用该函数来创建。
  • 13、subprocess.check_call(popenargs, **kwargs):与subprocess.call(popenargs, **kwargs)功能一样,只是如果子进程返回的returncode不为0的话,将触发CalledProcessError异常。在异常对象中,包括进程的returncode信息

示例:

>>> import subprocess
>>> subprocess.Popen('/apps/apache-tomcat-8.5.29/bin/startup.sh',shell=True)
<subprocess.Popen object at 0x7f3579b2dfd0>
>>> Using CATALINA_BASE:   /apps/apache-tomcat-8.5.29
Using CATALINA_HOME:   /apps/apache-tomcat-8.5.29
Using CATALINA_TMPDIR: /apps/apache-tomcat-8.5.29/temp
Using JRE_HOME:        /usr/java/jdk1.8.0_111/
Using CLASSPATH:       /apps/apache-tomcat-8.5.29/bin/bootstrap.jar:/apps/apache-tomcat-8.5.29/bin/tomcat-juli.jar
Tomcat started.

>>> popen = subprocess.Popen('tail -f /apps/apache-tomcat-8.5.29/logs/catalina.out',shell=True)
>>> 	at org.apache.tomcat.util.net.AbstractEndpoint.init(AbstractEndpoint.java:1086)
	at org.apache.tomcat.util.net.AbstractJsseEndpoint.init(AbstractJsseEndpoint.java:268)
	at org.apache.coyote.AbstractProtocol.init(AbstractProtocol.java:581)
	at org.apache.catalina.connector.Connector.initInternal(Connector.java:993)
	... 13 more

19-Nov-2019 17:05:05.020 信息 [main] org.apache.catalina.startup.Catalina.load Initialization processed in 650 ms
19-Nov-2019 17:05:05.045 信息 [main] org.apache.catalina.core.StandardService.startInternal Starting service [Catalina]
19-Nov-2019 17:05:05.045 信息 [main] org.apache.catalina.core.StandardEngine.startInternal Starting Servlet Engine: Apache Tomcat/8.5.29
19-Nov-2019 17:05:05.061 信息 [localhost-startStop-1] org.apache.catalina.startup.HostConfig.deployDirectory Deploying web application directory [/apps/apache-tomcat-8.5.29/webapps/ROOT]

KeyboardInterrupt
>>> popen.terminate()
>>> 

注意!

在shell=True这个参数,不写的时候默认是False,shell默认为/bin/sh。如果 args是一个字符串,则该字符串指定要通过shell执行的命令。
当需要设置shell=True时(当False时,arges是列表,第一个参数是shell命令,后面的都是参数',' 隔开),须把args设为string,空格隔开,如下

>>> a = subprocess.Popen(['tail','-f', '/apps/apache-tomcat-8.5.29/logs/catalina.out'])
>>> a = subprocess.Popen('tail -f /apps/apache-tomcat-8.5.29/logs/catalina.out',shell=True)
posted @ 2019-11-20 11:25  姜浩  阅读(7619)  评论(0编辑  收藏  举报