subprocess
*****本文参考了Vamei大神的http://www.cnblogs.com/vamei/archive/2012/09/23/2698014.html
运用subprocess包可以在运行python的进程下进一步开启一个子进程,创建子进程要注意
1. 父进程是否暂停
2.创建出的子进程返回了什么
3.执行出错,即返回的code不是0的时候应该如何处理
subprocess包提供了三个开启子进程的方法,subprocess.call() , subprocess.check_call() , subprocess.check_output(),给三者传递命令字符串作为参数。可以用([‘ping‘,‘www.baidu.com‘,‘-c‘,‘3‘])这种列表的形式,同时也可以是("ping www.baidu.com -c 3") 这种形式。在开启子进程的时候,可以加上shell=True的参数来让python开启一个shell,通过shell来解释获得的命令。一般在windows下运行的程序最好都把shell=True加上,这样才能顺利地执行dos命令,但是linux下似乎不加也没啥关系。因为linux下未指明用shell执行的话会调用/bin/sh来执行,问题不大,但是dos下系统不会默认用cmd.exe来执行命令,所以要加上shell=True。
subprocess.call ; subprocess.check_call ; subprocess.check_output 这三者的区别在于,返回的值分别是,子进程的执行返回码;若返回码是0则返回0,否则出错的话raise起CalledProcessError,可以用except处理之;若返回码是0则返回子进程向stdout输出的结果,否则也raise起CalledProcessError。另外,这三个方法都是让父进程挂起等待的,在子进程结束之前,父进程不会继续往下运行。
另外从本质上讲,上述三个方法都是对subprocess.Popen方法的一个包装,Popen开启的子进程是不会让父进程等待其完成的,除非调用了wait()方法:
child = subprocess.Popen("...",shell=True) print "Hello" """ 很可能hello在子进程的输出之前就被打印出来了,因为父进程不等child子进程运行完 """ child = subprocess.Popen("...",shell=True) child.wait() print "Hello" """ 这就不一样,父进程一定会等子进程运行完,给出完整的结果之后再继续往下执行。相当于wait函数挂起了父进程。 """
此外,上面代码里的child这个对象还有其他的一些方法:
child.poll() 返回子进程运行状态,主要是两种结果,None代表尚未运行,而一个返回码则代表已经运行完成并且是成功或失败了
child.kill() 强行终止子进程
child.send_signal(...) 向子进程发送一个信号(具体信号是以什么方式表示不清楚,还待研究)
child.terminate() 终止子进程
child.pid 子进程的pid
child.stdin/stdout/stderr 子进程的标准输入流,标准输出和标准错误输出,都是类文件对象
■ 文本流控制
每个子进程对象都有stdin/stdout/stderr三个对象,而在Popen开启子进程的时候,可以设置这三个对象。比如
child1 = subprocess.Popen("cmd1",shell=True, stdout=subprocess.PIPE) ‘‘‘ child1的stdout被设置成管道,可以把它理解成一个第三方托管机构, 因为不设置的话child1的stdout的内容就直接被打印到父进程的stdout里了, 设置成管道之后内容被导入了PIPEという名の第三方托管机构里 ‘‘‘ child2 = subprocess.Popen("cmd2",shell=True,stdin=child1.stdout,stdout=subprocess.PIPE) ‘‘‘ 把child2的stdin设置成了child1的stdout,也就是之前那个第三方机构,这么一来就实现了两个子进程之间的数据通信了。而把child2的stdout也设置成第三方,是因为不想让child2的输出就直接这么输出到父进程的stdout里,而要对它做一些处理 ‘‘‘ stdout,tmp = child2.communicate() ‘‘‘ 因为child2的输出不用再转给个child3去处理,就用communicate方法把第三方机构那里的数据取出来放进一个变量里。注意,这里的stdout已经是个str对象了,communicate出来的都是字符串了communicate方法自带wait功能,会让父进程挂起等待所有子进程结束communicate会返回一个元组,但是像在这个例子中没有设置stderr=PIPE,所以元组中的第二项原本属于stderr的值的地方的tmp的值是None,如果设置了其为PIPE,由于没有错误信息tmp是""。这点是有区别的。 ‘‘‘ print "We have result:\n%s"%(stdout) #代表了把stdout做一些处理后再输出
实际上,我一般都是这么干的:
import subprocess p = subprocess.Popen("CMD",shell=True,stdout=subprocess.PIPE,stderr=subprocess.PIPE) stdout,stderr = p.communicate() if stderr != "": print "ERROR:"+stderr else: print "RESULT:"+stdout