python模块subprocess学习

xiaoxiao2021-02-28  20

subprocess模块介绍

  subprocess是python创建子进程的工具,其实和c中的fork出一个子进程,然后在子进程中运行exec执行另外一个进程很类似。

  subprocess包中有很多方法创建子进程,这些函数创建子进程的行为不太一样,我们可以更具需求选择不同的方式来创建子进程。

  使用subprocess包中的函数创建子进程的时候,要注意:

  1) 在创建子进程之后,父进程是否暂停,并等待子进程运行。

  2) 函数返回什么

  3) 当returncode不为0时,父进程如何处理。

subprecess.call() 

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

 

 

 

  subprocess.check_call()

 

  父进程等待子进程完成

 

  返回0

 

  检查退出信息,如果returncode不为0,则举出错误subprocess.CalledProcessError,该对象包含有returncode属 性,可用try...except...来检查(见Python错误处理)。

 

 

 

  subprocess.check_output()

 

  父进程等待子进程完成

 

  返回子进程向标准输出的输出结果

 

  检查退出信息,如果returncode不为0,则举出错误subprocess.CalledProcessError,该对象包含有returncode属性和output属性,output属性为标准输出的输出结果,可用try...except...来检查。

  

1 #include <iostream> 2 #include <unistd.h> 3 4 using namespace std; 5 6 int main(int argc, const char *argv[]) 7 { 8 cout << "Python is powerful" << endl; 9 for (int i = 0; i < argc; i++) 10 { 11 cout << argv[i] << endl; 12 } 13 sleep(10); 14 return 0; 15 } 16 ~ 1 #!/usr/bin/env python 2 3 import subprocess 4 5 returnCode = subprocess.call('ls -l',shell=True) //我们使用了shell=True这个参数。这个时候,我们使用一整个字符串,而不是一个表来运行子进程。Python将先运行一个shell,再用这个shell来解释这整个字符串。 6 print "returnCode:",returnCode 7 8 returnCode = subprocess.call(['ls','-l']) //我们将程序名(ls)和所带的参数(-l)一起放在一个表中传递给subprocess.call() 9 print "returnCode:",returnCode 10 11 returnCode = subprocess.call(['./app','-a','-b','-c','-d']) //app也将参数和app本身以一个列表为传递过去12 print "returnCode:",returnCode

 

执行结果:

yca@ubuntu:~/Desktop/go$ ./assert.py total 1256 -rwxr-xr-x 1 yca yca 7785 2013-05-07 20:02 app -rw-r--r-- 1 yca yca 221 2013-05-07 20:01 app.cpp -rwxr-xr-x 1 yca yca 217 2013-05-07 20:40 assert.py -rwxr-xr-x 1 yca yca 1256270 2013-04-28 02:30 hello -rw-r--r-- 1 yca yca 396 2013-05-01 19:59 hello.go -rw-r--r-- 1 yca yca 918 2013-05-07 01:08 HelloWorld.go -rw-r--r-- 1 yca yca 556 2013-05-07 02:43 map.go returnCode: 0 Python is powerful ./app -a -b -c -d returnCode: 0

 

subprocess.Popen()

 上面三个函数都是对subprocess.Popen的封装,这些封装的目的是为了让我们容易使用子进程。当我们想要更个性化我们的需求的时候,就要转向Popen类,该类生成的对象用来代表子进程。

  与上面的封装不同,Popen对象创建后,主程序不会自动等待子进程完成。我们必须调用对象的wait()方法,父进程才会等待 (也就是阻塞block):

  

1 #!/usr/bin/env python 2 3 import subprocess 4 5 returnCode = subprocess.Popen(['./app','-a','-b','-c','-d']) 6 print "parent process"

 

yca@ubuntu:~/Desktop/go$ ./assert.py parent process yca@ubuntu:~/Desktop/go$ Python is powerful ./app -a -b -c -d

从运行结果中看到,父进程在开启子进程之后并没有等待child的完成,而是直接运行print。

  

1 #!/usr/bin/env python 2 3 import subprocess 4 5 child = subprocess.Popen(['./app','-a','-b','-c','-d']) 6 returnCode = child.wait() 7 print "returnCode:",returnCode8 print "parent process" yca@ubuntu:~/Desktop/go$ ./assert.py Python is powerful ./app -a -b -c -dreturnCode:0 parent process

很明显父进程在等待子进程执行完毕,才开始执行

此外,你还可以在父进程中对子进程进行其它操作,比如我们上面例子中的child对象:

child.poll()           # 检查子进程状态

child.kill()           # 终止子进程

child.send_signal()    # 向子进程发送信号

child.terminate()      # 终止子进程

 

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信息。

子进程的PID存储在child.pid

 

Popen对象 Popen对象有以下方法: Popen.poll() 检查子进程是否已结束,设置并返回 returncode 属性。 Popen.wait() 等待子进程结束,设置并返回 returncode 属性。 注意:如果子进程输出了大量数据到stdout或者stderr的管道,并达到了系统 pipe的缓存大小的话,子进程会等待父进程读取管道,而父进程此时正wait着的话,将会产生传说中的死锁,后果是非常严重滴。建议使用communicate()来 避免这种情况的发生。 Popen.communicate(input=None) 和子进程交互:发送数据到stdin,并从stdout和stderr读数据,直到收到EOF。等待子进程结束。可选的input如有 有的话,要为字符串类型。 此函数返回一个元组: (stdoutdata, stderrdata) 。 注意,要给子进程的stdin发送数据,则Popen的时候,stdin要为PIPE;同理,要可以收数据的话,stdout或者stderr也要为 PIPE。 注意:读到的数据会被缓存在内存里,所以数据量非常大的时候要小心了。 Popen.send_signal(signal) 给子进程发送signal信号量。 注意:windows下目前只支持发送SIGTERM,等效于下面的terminate()。 Popen.terminate() 停止子进程。Posix下是发送SIGTERM信号。windows下是调用TerminateProcess()这 个API。 Popen.kill() 杀死子进程。Posix下是发送SIGKILL信号。windows下和terminate()无异。 Popen.stdin 如果stdin参数是PIPE,此属性就是一个文件对象,否则为None。 Popen.stdout 如果stdout参数是PIPE,此属性就是一个文件对象,否则为None。 Popen.stderr 如果stderr参数是PIPE,此属性就是一个文件对象,否则为None。 Popen.pid 子进程的进程号。注意,如果shell参数为True,这属性指的是子shell的进程号。 Popen.returncode 子程序的返回值,由poll()或者wait()设置,间接地也由communicate()设置。 如果为None,表示子进程还没终止。 如果为负数-N的话,表示子进程被N号信号终止。(仅限*nux)

http://blog.csdn.net/mr_jj_lian/article/details/6936984

3. 子进程的文本流控制

(沿用child子进程) 子进程的标准输入,标准输出和标准错误也可以通过如下属性表示:

child.stdin

child.stdout

child.stderr

 

我们可以在Popen()建立子进程的时候改变标准输入、标准输出和标准错误,并可以利用subprocess.PIPE将多个子进程的输入和输出连接在一起,构成管道(pipe):

1 #!/usr/bin/env python 2 3 import subprocess 4 5 child1 = subprocess.Popen(["ls","-l"], stdout=subprocess.PIPE) 6 child2 = subprocess.Popen(["wc"], stdin=child1.stdout,stdout=subprocess.PIPE) 7 out = child2.communicate() 8 print out

child1.stdout-->subprocess.PIPE

child2.stdin<--subprocess.PIPE        

child2.stdout-->subprocess.PIPE

相当于将child1.stdout-->child2.stdin->child2.stdout->subprocess.PIPE

subprocess.PIPE实际上为文本流提供一个缓存区。child1的stdout将文本输出到缓存区,随后child2的stdin从该PIPE中将文本读取走。child2的输出文本也被存放在PIPE中,直到communicate()方法从PIPE中读取出PIPE中的文本。

要注意的是,communicate()是Popen对象的一个方法,该方法会阻塞父进程,直到子进程完成

 

我们还可以利用communicate()方法来使用PIPE给子进程输入:

 

1 import subprocess 2 child = subprocess.Popen(["cat"], stdin=subprocess.PIPE) 3 child.communicate("vamei") //()不为空,则写入subprocess.PIPE,为空,则从subprocess.PIPE读取 subprocess.PIPE-->child.stdincommiuncate相当于写入subprocess.PIPE,然后child从subprocess.PIPE读取 returnCode

  执行子进程后的返回值是从何而来呢?通过exit的返回值得到

  

1 #!/bin/bash 2 3 echo "hello" 4 exit 1 5 ~

 

 

 

1 #!/usr/bin/env python 2 3 import subprocess 4 5 child = subprocess.Popen(["./shell.sh"], stdout=subprocess.PIPE) 6 returnCode = child.wait() 7 print "returnCode:",returnCode 8 stdout = child.communicate() 9 print stdout

 

yca@ubuntu:~/Desktop/go$ ./assert.py returnCode: 1 ('hello\n', None)
转载请注明原文地址: https://www.6miu.com/read-2150113.html

最新回复(0)