blob: e0f2880e7562dc847e42b38a7c6ed5d60e2d8cde [file] [log] [blame]
Guido van Rossum54f22ed2000-02-04 15:10:34 +00001"""Spawn a command with pipes to its stdin, stdout, and optionally stderr.
2
3The normal os.popen(cmd, mode) call spawns a shell command and provides a
4file interface to just the input or output of the process depending on
5whether mode is 'r' or 'w'. This module provides the functions popen2(cmd)
6and popen3(cmd) which return two or three pipes to the spawned command.
7"""
8
Guido van Rossum9a22de11995-01-12 12:29:47 +00009import os
10import sys
11import string
12
Guido van Rossum45e2fbc1998-03-26 21:13:24 +000013MAXFD = 256 # Max number of file descriptors (os.getdtablesize()???)
Guido van Rossum9a22de11995-01-12 12:29:47 +000014
Guido van Rossum0357d021997-08-11 03:27:24 +000015_active = []
16
17def _cleanup():
18 for inst in _active[:]:
Guido van Rossum45e2fbc1998-03-26 21:13:24 +000019 inst.poll()
Guido van Rossum0357d021997-08-11 03:27:24 +000020
21class Popen3:
Guido van Rossum54f22ed2000-02-04 15:10:34 +000022 """Class representing a child process. Normally instances are created
23 by the factory functions popen2() and popen3()."""
24
Guido van Rossumda286661997-09-29 04:04:39 +000025 def __init__(self, cmd, capturestderr=0, bufsize=-1):
Guido van Rossum54f22ed2000-02-04 15:10:34 +000026 """The parameter 'cmd' is the shell command to execute in a
27 sub-process. The 'capturestderr' flag, if true, specifies that
28 the object should capture standard error output of the child process.
29 The default is false. If the 'bufsize' parameter is specified, it
30 specifies the size of the I/O buffers to/from the child process."""
Guido van Rossum45e2fbc1998-03-26 21:13:24 +000031 if type(cmd) == type(''):
32 cmd = ['/bin/sh', '-c', cmd]
33 p2cread, p2cwrite = os.pipe()
34 c2pread, c2pwrite = os.pipe()
35 if capturestderr:
36 errout, errin = os.pipe()
37 self.pid = os.fork()
38 if self.pid == 0:
39 # Child
40 os.close(0)
41 os.close(1)
42 if os.dup(p2cread) <> 0:
43 sys.stderr.write('popen2: bad read dup\n')
44 if os.dup(c2pwrite) <> 1:
45 sys.stderr.write('popen2: bad write dup\n')
46 if capturestderr:
47 os.close(2)
48 if os.dup(errin) <> 2: pass
49 for i in range(3, MAXFD):
50 try:
51 os.close(i)
52 except: pass
53 try:
54 os.execvp(cmd[0], cmd)
55 finally:
56 os._exit(1)
57 # Shouldn't come here, I guess
58 os._exit(1)
59 os.close(p2cread)
60 self.tochild = os.fdopen(p2cwrite, 'w', bufsize)
61 os.close(c2pwrite)
62 self.fromchild = os.fdopen(c2pread, 'r', bufsize)
63 if capturestderr:
64 os.close(errin)
65 self.childerr = os.fdopen(errout, 'r', bufsize)
66 else:
67 self.childerr = None
68 self.sts = -1 # Child not completed yet
69 _active.append(self)
Guido van Rossum54f22ed2000-02-04 15:10:34 +000070
Guido van Rossum0357d021997-08-11 03:27:24 +000071 def poll(self):
Guido van Rossum54f22ed2000-02-04 15:10:34 +000072 """Return the exit status of the child process if it has finished,
73 or -1 if it hasn't finished yet."""
Guido van Rossum45e2fbc1998-03-26 21:13:24 +000074 if self.sts < 0:
75 try:
76 pid, sts = os.waitpid(self.pid, os.WNOHANG)
77 if pid == self.pid:
78 self.sts = sts
79 _active.remove(self)
80 except os.error:
81 pass
82 return self.sts
Guido van Rossum54f22ed2000-02-04 15:10:34 +000083
Guido van Rossum0357d021997-08-11 03:27:24 +000084 def wait(self):
Guido van Rossum54f22ed2000-02-04 15:10:34 +000085 """Wait for and return the exit status of the child process."""
Guido van Rossum45e2fbc1998-03-26 21:13:24 +000086 pid, sts = os.waitpid(self.pid, 0)
87 if pid == self.pid:
88 self.sts = sts
89 _active.remove(self)
90 return self.sts
Guido van Rossumcaa9f231997-04-21 14:15:55 +000091
Fred Drake31f182e2000-08-28 17:20:05 +000092
93if sys.platform[:3] == "win":
Fredrik Lundh9ac81f62000-07-09 23:35:24 +000094 def popen2(cmd, mode='t', bufsize=-1):
95 """Execute the shell command 'cmd' in a sub-process. If 'bufsize' is
96 specified, it sets the buffer size for the I/O pipes. The file objects
97 (child_stdout, child_stdin) are returned."""
98 w, r = os.popen2(cmd, mode, bufsize)
99 return r, w
100else:
Fredrik Lundhbb7eeff2000-07-09 17:59:32 +0000101 def popen2(cmd, mode='t', bufsize=-1):
102 """Execute the shell command 'cmd' in a sub-process. If 'bufsize' is
103 specified, it sets the buffer size for the I/O pipes. The file objects
104 (child_stdout, child_stdin) are returned."""
105 if type(mode) is type(0) and bufsize == -1:
106 bufsize = mode
107 mode = 't'
108 assert mode in ('t', 'b')
109 _cleanup()
110 inst = Popen3(cmd, 0, bufsize)
111 return inst.fromchild, inst.tochild
Guido van Rossumcaa9f231997-04-21 14:15:55 +0000112
Fred Drake31f182e2000-08-28 17:20:05 +0000113if sys.platform[:3] == "win":
Fredrik Lundh9ac81f62000-07-09 23:35:24 +0000114 def popen3(cmd, mode='t', bufsize=-1):
115 """Execute the shell command 'cmd' in a sub-process. If 'bufsize' is
116 specified, it sets the buffer size for the I/O pipes. The file objects
117 (child_stdout, child_stdin, child_stderr) are returned."""
118 w, r, e = os.popen3(cmd, mode, bufsize)
119 return r, w, e
120else:
Fredrik Lundhbb7eeff2000-07-09 17:59:32 +0000121 def popen3(cmd, mode='t', bufsize=-1):
122 """Execute the shell command 'cmd' in a sub-process. If 'bufsize' is
123 specified, it sets the buffer size for the I/O pipes. The file objects
124 (child_stdout, child_stdin, child_stderr) are returned."""
125 if type(mode) is type(0) and bufsize == -1:
126 bufsize = mode
127 mode = 't'
128 assert mode in ('t', 'b')
129 _cleanup()
130 inst = Popen3(cmd, 1, bufsize)
131 return inst.fromchild, inst.tochild, inst.childerr
132
Fred Drake31f182e2000-08-28 17:20:05 +0000133if sys.platform[:3] == "win":
Fredrik Lundh9ac81f62000-07-09 23:35:24 +0000134 def popen4(cmd, mode='t', bufsize=-1):
135 """Execute the shell command 'cmd' in a sub-process. If 'bufsize' is
136 specified, it sets the buffer size for the I/O pipes. The file objects
137 (child_stdout_stderr, child_stdin) are returned."""
138 w, r = os.popen4(cmd, mode, bufsize)
139 return r, w
140else:
141 pass # not yet on unix
Guido van Rossum0357d021997-08-11 03:27:24 +0000142
Fred Drake31f182e2000-08-28 17:20:05 +0000143
Guido van Rossum0357d021997-08-11 03:27:24 +0000144def _test():
Tim Peters84f28db2000-08-20 05:57:36 +0000145 cmd = "cat"
Guido van Rossum0357d021997-08-11 03:27:24 +0000146 teststr = "abc\n"
Tim Peters84f28db2000-08-20 05:57:36 +0000147 resultstr = teststr
148 if os.name == "nt":
149 cmd = "more"
150 resultstr = "\n" + resultstr
Guido van Rossum0357d021997-08-11 03:27:24 +0000151 print "testing popen2..."
Tim Peters84f28db2000-08-20 05:57:36 +0000152 r, w = popen2(cmd)
Guido van Rossum0357d021997-08-11 03:27:24 +0000153 w.write(teststr)
154 w.close()
Tim Peters84f28db2000-08-20 05:57:36 +0000155 assert r.read() == resultstr
Guido van Rossum0357d021997-08-11 03:27:24 +0000156 print "testing popen3..."
Fredrik Lundhbb7eeff2000-07-09 17:59:32 +0000157 try:
Tim Peters84f28db2000-08-20 05:57:36 +0000158 r, w, e = popen3([cmd])
Fredrik Lundhbb7eeff2000-07-09 17:59:32 +0000159 except:
Tim Peters84f28db2000-08-20 05:57:36 +0000160 r, w, e = popen3(cmd)
Guido van Rossum0357d021997-08-11 03:27:24 +0000161 w.write(teststr)
162 w.close()
Tim Peters84f28db2000-08-20 05:57:36 +0000163 assert r.read() == resultstr
Guido van Rossum0357d021997-08-11 03:27:24 +0000164 assert e.read() == ""
Guido van Rossum068d5721999-04-20 12:27:31 +0000165 for inst in _active[:]:
166 inst.wait()
Guido van Rossum0357d021997-08-11 03:27:24 +0000167 assert not _active
168 print "All OK"
169
170if __name__ == '__main__':
171 _test()