self-confidence,the source of all the power

导航

subprocess

http://docs.python.org/library/subprocess.html

1.执行shell命令

官方定义:

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

Run the command described by args. Wait for command to complete, then return the returncode attribute.

#!/usr/bin/env python  
   #Python wrapper for the ls command  
    import subprocess  
    subprocess.call(["ls","-l"]) 
    或者subprocess.call("ls -l",shell=True)

2.subprocess.Popen

   class subprocess.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)

各参数含义如下:

  args需要是一个字符串,或者包含程序参数的列表。要执行的程序一般就是这个列表的第一项,或者是字符串本身。但是也可以用executable参数来明确指出。当executable参数不为空时,args里的第一项仍被认为是程序的“命令名”,不同于真正的可执行文件的文件名,这个“命令名”是一个用来显示的名称,例如执行*nix下的 ps 命令,显示出来的就是这个“命令名”。

在*nix下,当shell=False(默认)时,Popen使用os.execvp()来执行子程序。args一般要是一个列表。如果args是个字符串的话,会被当做是可执行文件的路径,这样就不能传入任何参数了。

例子(借用别人的):

p = subprocess.Popen("app2.exe", stdin = subprocess.PIPE, /  
    stdout = subprocess.PIPE, stderr = subprocess.PIPE, shell = False)  
p.stdin.write('3/n')  
p.stdin.write('4/n')  
print p.stdout.read()  
  
#---- 结果 ----   
input x:   
input y:   
3 + 4 = 7  

app2 code:

#include <iostream>   
using namespace std;  
int main(int argc, const char *artv[])  
{  
    int x, y;  
    cout << "input x: " << endl;  
    cin >> x;  
    cout << "input y: " << endl;  
    cin >> y;  
    cout << x << " + " << y << " = " << x + y << endl;  
    return 0;  
}  

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)

用subprocess来代替其他函数

在这节里,举一些常用的例子,都可以用subprocess来完成,我们假定是用 “from subprocess import *” 来导入模块的:

代替shell命令:

output=`mycmd myarg`
等效于
output = Popen(["mycmd", "myarg"], stdout=PIPE).communicate()[0]

代替shell管道:

output=`dmesg | grep hda`
等效于
p1 = Popen(["dmesg"], stdout=PIPE)
p2 = Popen(["grep", "hda"], stdin=p1.stdout, stdout=PIPE)
output = p2.communicate()[0]

代替os.system()

sts = os.system(“mycmd” + ” myarg”)
等效于
p = Popen(“mycmd” + ” myarg”, shell=True)
sts = os.waitpid(p.pid, 0)[1]

注意:

  • 通常并不需要用shell来调用程序。
  • 用subprocess可以更方便地得到子程序的返回值。

其实,更真实的替换是:

try:
retcode = call(“mycmd” + ” myarg”, shell=True)
if retcode < 0:
print >>sys.stderr, “Child was terminated by signal”, -retcode
else:
print >>sys.stderr, “Child returned”, retcode
except OSError, e:
print >>sys.stderr, “Execution failed:”, e

代替os.spawn系列
P_NOWAIT的例子

pid = os.spawnlp(os.P_NOWAIT, “/bin/mycmd”, “mycmd”, “myarg”)
等效于
pid = Popen(["/bin/mycmd", "myarg"]).pid

P_WAIT的例子

retcode = os.spawnlp(os.P_WAIT, “/bin/mycmd”, “mycmd”, “myarg”)
等效于
retcode = call(["/bin/mycmd", "myarg"])

Vector的例子

os.spawnvp(os.P_NOWAIT, path, args)
等效于
Popen([path] + args[1:])

关于环境变量的例子

os.spawnlpe(os.P_NOWAIT, “/bin/mycmd”, “mycmd”, “myarg”, env)
等效于
Popen(["/bin/mycmd", "myarg"], env={“PATH”: “/usr/bin”})

代替os.popen(), os.popen2(), os.popen3()

pipe = os.popen(“cmd”, ‘r’, bufsize)
等效于
pipe = Popen(“cmd”, shell=True, bufsize=bufsize, stdout=PIPE).stdout

pipe = os.popen(“cmd”, ‘w’, bufsize)
等效于
pipe = Popen(“cmd”, shell=True, bufsize=bufsize, stdin=PIPE).stdin

(child_stdin, child_stdout) = os.popen2(“cmd”, mode, bufsize)
等效于
p = Popen(“cmd”, shell=True, bufsize=bufsize, stdin=PIPE, stdout=PIPE, close_fds=True)
(child_stdin, child_stdout) = (p.stdin, p.stdout)

(child_stdin, child_stdout, child_stderr) = os.popen3(“cmd”, mode, bufsize)
等效于
p = Popen(“cmd”, shell=True, bufsize=bufsize, stdin=PIPE, stdout=PIPE, stderr=PIPE, close_fds=True)
(child_stdin, child_stdout, child_stderr) = (p.stdin, p.stdout, p.stderr)

(child_stdin, child_stdout_and_stderr) = os.popen4(“cmd”, mode, bufsize)
等效于
p = Popen(“cmd”, shell=True, bufsize=bufsize, stdin=PIPE, stdout=PIPE, stderr=STDOUT, close_fds=True)
(child_stdin, child_stdout_and_stderr) = (p.stdin, p.stdout)

*nix下,os.popen2, os.popen3, os.popen4 也可以接受一个列表做为执行的命令,这时参数会被直接传给程序,而不经过shell的解释转换。如下:

(child_stdin, child_stdout) = os.popen2(["/bin/ls", "-l"], mode, bufsize)
等效于
p = Popen(["/bin/ls", "-l"], bufsize=bufsize, stdin=PIPE, stdout=PIPE)
(child_stdin, child_stdout) = (p.stdin, p.stdout)

返回值处理:

pipe = os.popen(“cmd”, ‘w’)

rc = pipe.close()
if rc != None and rc % 256:
print “There were some errors”
等效于
process = Popen(“cmd”, ‘w’, shell=True, stdin=PIPE)

process.stdin.close()
if process.wait() != 0:
print “There were some errors”

代替popen2模块里的函数:

(child_stdout, child_stdin) = popen2.popen2(“somestring”, bufsize, mode)
等效于
p = Popen(["somestring"], shell=True, bufsize=bufsize, stdin=PIPE, stdout=PIPE, close_fds=True)
(child_stdout, child_stdin) = (p.stdout, p.stdin)

*nix下,popen2 也可以接受一个列表做为执行的命令,这时参数会被直接传给程序,而不经过shell的解释转换。如下:

(child_stdout, child_stdin) = popen2.popen2(["mycmd", "myarg"], bufsize, mode)
等效于
p = Popen(["mycmd", "myarg"], bufsize=bufsize, stdin=PIPE, stdout=PIPE, close_fds=True)
(child_stdout, child_stdin) = (p.stdout, p.stdin)

popen2.Popen3 and popen2.Popen4 基本上也能用 subprocess.Popen 代替,除了以下几点要注意:

  • 执行失败的时候Popen会抛出异常
  • capturestderr参数用stderr代替
  • stdin=PIPEstdout=PIPE 必须要指定
  • popen2默认会关掉所有文件描述符,而Popen要指定close_fds=True

 

3.shlex.split()可以被用于序列化复杂的命令参数

>>> command = raw_input()
cd d: dir
>>> command
'cd d: dir'
>>> import shlex
>>> args = shlex.split(command)
>>> args
['cd', 'd:', 'dir']

import subprocess

p = subprocess.Popen(cmd, stderr = subprocess.STDOUT, stdout= subprocess.PIPE, shell = True)
return_str=p.stdout.read()
#stderr output handle way as the stdout

 

posted on 2012-09-12 16:28  漩涡鸣人  阅读(794)  评论(0编辑  收藏  举报