blob: 4580f5873ad1f50e1ac3907269ee9aa6e151ce1a [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
Guido van Rossum9a22de11995-01-12 12:29:47 +000011
Guido van Rossum45e2fbc1998-03-26 21:13:24 +000012MAXFD = 256 # Max number of file descriptors (os.getdtablesize()???)
Guido van Rossum9a22de11995-01-12 12:29:47 +000013
Guido van Rossum0357d021997-08-11 03:27:24 +000014_active = []
15
16def _cleanup():
17 for inst in _active[:]:
Guido van Rossum45e2fbc1998-03-26 21:13:24 +000018 inst.poll()
Guido van Rossum0357d021997-08-11 03:27:24 +000019
20class Popen3:
Guido van Rossum54f22ed2000-02-04 15:10:34 +000021 """Class representing a child process. Normally instances are created
22 by the factory functions popen2() and popen3()."""
23
Fred Draked75e63a2000-09-28 19:07:53 +000024 sts = -1 # Child not completed yet
25
Guido van Rossumda286661997-09-29 04:04:39 +000026 def __init__(self, cmd, capturestderr=0, bufsize=-1):
Guido van Rossum54f22ed2000-02-04 15:10:34 +000027 """The parameter 'cmd' is the shell command to execute in a
28 sub-process. The 'capturestderr' flag, if true, specifies that
29 the object should capture standard error output of the child process.
30 The default is false. If the 'bufsize' parameter is specified, it
31 specifies the size of the I/O buffers to/from the child process."""
Fred Draked75e63a2000-09-28 19:07:53 +000032 _cleanup()
Guido van Rossum45e2fbc1998-03-26 21:13:24 +000033 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
Fred Draked75e63a2000-09-28 19:07:53 +000040 os.dup2(p2cread, 0)
41 os.dup2(c2pwrite, 1)
Guido van Rossum45e2fbc1998-03-26 21:13:24 +000042 if capturestderr:
Fred Draked75e63a2000-09-28 19:07:53 +000043 os.dup2(errin, 2)
44 self._run_child(cmd)
Guido van Rossum45e2fbc1998-03-26 21:13:24 +000045 os.close(p2cread)
46 self.tochild = os.fdopen(p2cwrite, 'w', bufsize)
47 os.close(c2pwrite)
48 self.fromchild = os.fdopen(c2pread, 'r', bufsize)
49 if capturestderr:
50 os.close(errin)
51 self.childerr = os.fdopen(errout, 'r', bufsize)
52 else:
53 self.childerr = None
Guido van Rossum45e2fbc1998-03-26 21:13:24 +000054 _active.append(self)
Guido van Rossum54f22ed2000-02-04 15:10:34 +000055
Fred Draked75e63a2000-09-28 19:07:53 +000056 def _run_child(self, cmd):
57 if type(cmd) == type(''):
58 cmd = ['/bin/sh', '-c', cmd]
59 for i in range(3, MAXFD):
60 try:
61 os.close(i)
62 except:
63 pass
64 try:
65 os.execvp(cmd[0], cmd)
66 finally:
67 os._exit(1)
68
Guido van Rossum0357d021997-08-11 03:27:24 +000069 def poll(self):
Guido van Rossum54f22ed2000-02-04 15:10:34 +000070 """Return the exit status of the child process if it has finished,
71 or -1 if it hasn't finished yet."""
Guido van Rossum45e2fbc1998-03-26 21:13:24 +000072 if self.sts < 0:
73 try:
74 pid, sts = os.waitpid(self.pid, os.WNOHANG)
75 if pid == self.pid:
76 self.sts = sts
77 _active.remove(self)
78 except os.error:
79 pass
80 return self.sts
Guido van Rossum54f22ed2000-02-04 15:10:34 +000081
Guido van Rossum0357d021997-08-11 03:27:24 +000082 def wait(self):
Guido van Rossum54f22ed2000-02-04 15:10:34 +000083 """Wait for and return the exit status of the child process."""
Guido van Rossum45e2fbc1998-03-26 21:13:24 +000084 pid, sts = os.waitpid(self.pid, 0)
85 if pid == self.pid:
86 self.sts = sts
87 _active.remove(self)
88 return self.sts
Guido van Rossumcaa9f231997-04-21 14:15:55 +000089
Fred Drake31f182e2000-08-28 17:20:05 +000090
Fred Draked75e63a2000-09-28 19:07:53 +000091class Popen4(Popen3):
92 childerr = None
93
94 def __init__(self, cmd, bufsize=-1):
95 _cleanup()
96 p2cread, p2cwrite = os.pipe()
97 c2pread, c2pwrite = os.pipe()
98 self.pid = os.fork()
99 if self.pid == 0:
100 # Child
101 os.dup2(p2cread, 0)
102 os.dup2(c2pwrite, 1)
103 os.dup2(c2pwrite, 2)
104 self._run_child(cmd)
105 os.close(p2cread)
106 self.tochild = os.fdopen(p2cwrite, 'w', bufsize)
107 os.close(c2pwrite)
108 self.fromchild = os.fdopen(c2pread, 'r', bufsize)
109 _active.append(self)
110
111
Fred Drake31f182e2000-08-28 17:20:05 +0000112if sys.platform[:3] == "win":
Fred Draked75e63a2000-09-28 19:07:53 +0000113 # Some things don't make sense on non-Unix platforms.
114 del Popen3, Popen4, _active, _cleanup
115
116 def popen2(cmd, bufsize=-1, mode='t'):
Fredrik Lundh9ac81f62000-07-09 23:35:24 +0000117 """Execute the shell command 'cmd' in a sub-process. If 'bufsize' is
118 specified, it sets the buffer size for the I/O pipes. The file objects
119 (child_stdout, child_stdin) are returned."""
120 w, r = os.popen2(cmd, mode, bufsize)
121 return r, w
Guido van Rossumcaa9f231997-04-21 14:15:55 +0000122
Fred Draked75e63a2000-09-28 19:07:53 +0000123 def popen3(cmd, bufsize=-1, mode='t'):
Fredrik Lundh9ac81f62000-07-09 23:35:24 +0000124 """Execute the shell command 'cmd' in a sub-process. If 'bufsize' is
125 specified, it sets the buffer size for the I/O pipes. The file objects
126 (child_stdout, child_stdin, child_stderr) are returned."""
127 w, r, e = os.popen3(cmd, mode, bufsize)
128 return r, w, e
Fredrik Lundhbb7eeff2000-07-09 17:59:32 +0000129
Fred Draked75e63a2000-09-28 19:07:53 +0000130 def popen4(cmd, bufsize=-1, mode='t'):
Fredrik Lundh9ac81f62000-07-09 23:35:24 +0000131 """Execute the shell command 'cmd' in a sub-process. If 'bufsize' is
132 specified, it sets the buffer size for the I/O pipes. The file objects
133 (child_stdout_stderr, child_stdin) are returned."""
134 w, r = os.popen4(cmd, mode, bufsize)
135 return r, w
136else:
Fred Draked75e63a2000-09-28 19:07:53 +0000137 def popen2(cmd, bufsize=-1, mode='t'):
138 """Execute the shell command 'cmd' in a sub-process. If 'bufsize' is
139 specified, it sets the buffer size for the I/O pipes. The file objects
140 (child_stdout, child_stdin) are returned."""
141 inst = Popen3(cmd, 0, bufsize)
142 return inst.fromchild, inst.tochild
143
144 def popen3(cmd, bufsize=-1, mode='t'):
145 """Execute the shell command 'cmd' in a sub-process. If 'bufsize' is
146 specified, it sets the buffer size for the I/O pipes. The file objects
147 (child_stdout, child_stdin, child_stderr) are returned."""
148 inst = Popen3(cmd, 1, bufsize)
149 return inst.fromchild, inst.tochild, inst.childerr
150
151 def popen4(cmd, bufsize=-1, mode='t'):
152 """Execute the shell command 'cmd' in a sub-process. If 'bufsize' is
153 specified, it sets the buffer size for the I/O pipes. The file objects
154 (child_stdout_stderr, child_stdin) are returned."""
155 inst = Popen4(cmd, bufsize)
156 return inst.fromchild, inst.tochild
Guido van Rossum0357d021997-08-11 03:27:24 +0000157
Fred Drake31f182e2000-08-28 17:20:05 +0000158
Guido van Rossum0357d021997-08-11 03:27:24 +0000159def _test():
Tim Peters84f28db2000-08-20 05:57:36 +0000160 cmd = "cat"
Tim Peters36208572000-09-01 20:38:55 +0000161 teststr = "ab cd\n"
Tim Peters84f28db2000-08-20 05:57:36 +0000162 if os.name == "nt":
163 cmd = "more"
Tim Peters36208572000-09-01 20:38:55 +0000164 # "more" doesn't act the same way across Windows flavors,
165 # sometimes adding an extra newline at the start or the
166 # end. So we strip whitespace off both ends for comparison.
167 expected = teststr.strip()
Guido van Rossum0357d021997-08-11 03:27:24 +0000168 print "testing popen2..."
Tim Peters84f28db2000-08-20 05:57:36 +0000169 r, w = popen2(cmd)
Guido van Rossum0357d021997-08-11 03:27:24 +0000170 w.write(teststr)
171 w.close()
Tim Peters36208572000-09-01 20:38:55 +0000172 got = r.read()
173 if got.strip() != expected:
174 raise ValueError("wrote %s read %s" % (`teststr`, `got`))
Guido van Rossum0357d021997-08-11 03:27:24 +0000175 print "testing popen3..."
Fredrik Lundhbb7eeff2000-07-09 17:59:32 +0000176 try:
Tim Peters84f28db2000-08-20 05:57:36 +0000177 r, w, e = popen3([cmd])
Fredrik Lundhbb7eeff2000-07-09 17:59:32 +0000178 except:
Tim Peters84f28db2000-08-20 05:57:36 +0000179 r, w, e = popen3(cmd)
Guido van Rossum0357d021997-08-11 03:27:24 +0000180 w.write(teststr)
181 w.close()
Tim Peters36208572000-09-01 20:38:55 +0000182 got = r.read()
183 if got.strip() != expected:
184 raise ValueError("wrote %s read %s" % (`teststr`, `got`))
185 got = e.read()
186 if got:
187 raise ValueError("unexected %s on stderr" % `got`)
Guido van Rossum068d5721999-04-20 12:27:31 +0000188 for inst in _active[:]:
189 inst.wait()
Tim Peters36208572000-09-01 20:38:55 +0000190 if _active:
191 raise ValueError("_active not empty")
Guido van Rossum0357d021997-08-11 03:27:24 +0000192 print "All OK"
193
194if __name__ == '__main__':
195 _test()