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:
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=PIPE
和stdout=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