Subprocess Module
今天使用subprocess给TA的课程cs354写了一点测试脚本,研究了一下subprocess这个module。原来上操作系统课程每天只是听说进程间通信是几种方式,Pipe管道、共享内存、Socket、消息队列MQ等等。从来没有用过Pipe,只使用过shared_memory(shmmem).今天用了一次才发现了大坑。
总的来说Subprocess定义了几个在子进程中执行一些其他命令的方式:
The subprocess module allows you to spawn new processes, connect to their input/output/error pipes, and obtain their return codes. This module intends to replace several older modules and functions:
os.system
os.spawn
os.popen
popen2.
commands.
The recommended way to launch subprocesses is to use the following convenience functions.subprocess.call(args, *, stdin=None, stdout=None, stderr=None, shell=False),分别指定输入输出来源,返回returncode属性,shell=True是一个危险行为.Do not use stdout=PIPE or stderr=PIPE with this function as that can deadlock based on the child process output volume. Use Popen with the communicate() method when you need pipes.需要通信的时候需要使用Popen,避免直接使用Call.
subprocess.PIPE:Special value that can be used as the stdin, stdout or stderr argument to Popen and indicates that a pipe to the standard stream should be opened.
subprocess.STDOUT:Special value that can be used as the stderr argument to Popen and indicates that standard error should go into the same handle as standard output.
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):在子进程中执行子程序,The shell argument (which defaults to False) specifies whether to use the shell as the program to execute. If shell is True, it is recommended to pass args as a string rather than as a sequence.
stdin, stdout and stderr specify the executed program’s standard input, standard output and standard error file handles, respectively. Valid values are PIPE, an existing file descriptor (a positive integer), an existing file object, and None. PIPE indicates that a new pipe to the child should be created. With the default settings of None, no redirection will occur; the child’s file handles will be inherited from the parent. Additionally, stderr can be STDOUT, which indicates that the stderr data from the child process should be captured into the same file handle as for stdout.
If cwd is not None, the child’s current directory will be changed to cwd before it is executed. 子进程切换到cwd目录执行.
Popen.communicate(input=None)和进程进行交互,向进程传递数据,比如C程序让你输参数.
Interact with process: Send data to stdin. Read data from stdout and stderr, until end-of-file is reached. Wait for process to terminate. The optional input argument should be a string to be sent to the child process, or None, if no data should be sent to the child.
communicate() returns a tuple (stdoutdata, stderrdata).
Note that if you want to send data to the process’s stdin, you need to create the Popen object with stdin=PIPE. Similarly, to get anything other than None in the result tuple, you need to give stdout=PIPE and/or stderr=PIPE too.
Popen.kill():Kills the child.
Popen.wait():Wait for child process to terminate.
代码如下,自己定义的subcall子函数调用其他.c命令或者程序。Popen用的比较多的参数是第一个args,也就是你的管道要执行的命令参数,除此之外还有一个cwd_path是执行命令会切换到的绝对路径,当需要向文件写入pipe内容时,stdout需要给出文件句柄作为参数,log = open('test','w');stdout = log
.1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19def subcall(args, cwd_path, timeout=None, input=None, generate=False, file=None):
os.environ['LIBC_FATAL_STDERR_'] = 'NOT_EMPTY'
if generate == False:
with Popen(args, stdin=subprocess.PIPE, stdout=subprocess.PIPE, stderr=subprocess.PIPE, cwd=cwd_path) as proc:
try:
outs, errs = proc.communicate(timeout=timeout, input=input)
except TimeoutExpired:
proc.kill()
outs, errs = proc.communicate()
ret = proc.returncode
else:
with Popen(args, stdin=subprocess.PIPE, stdout=file, stderr=subprocess.PIPE, cwd=cwd_path) as proc:
try:
outs, errs = proc.communicate(timeout=timeout, input=input)
except TimeoutExpired:
proc.kill()
outs, errs = proc.communicate()
ret = proc.returncode
return outs, errs, ret