blob: f00cb833fdc7a64d08111cd231de2d12d5bef613 [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
Martin v. Löwis95b057e2001-12-02 13:32:15 +000011import types
Guido van Rossum9a22de11995-01-12 12:29:47 +000012
Skip Montanaro57fd45e2002-03-12 19:48:03 +000013__all__ = ["popen2", "popen3", "popen4"]
Skip Montanaro352674d2001-02-07 23:14:30 +000014
Guido van Rossum45e2fbc1998-03-26 21:13:24 +000015MAXFD = 256 # Max number of file descriptors (os.getdtablesize()???)
Guido van Rossum9a22de11995-01-12 12:29:47 +000016
Guido van Rossum0357d021997-08-11 03:27:24 +000017_active = []
18
19def _cleanup():
20 for inst in _active[:]:
Guido van Rossum45e2fbc1998-03-26 21:13:24 +000021 inst.poll()
Guido van Rossum0357d021997-08-11 03:27:24 +000022
23class Popen3:
Guido van Rossum54f22ed2000-02-04 15:10:34 +000024 """Class representing a child process. Normally instances are created
25 by the factory functions popen2() and popen3()."""
26
Fred Draked75e63a2000-09-28 19:07:53 +000027 sts = -1 # Child not completed yet
28
Guido van Rossumda286661997-09-29 04:04:39 +000029 def __init__(self, cmd, capturestderr=0, bufsize=-1):
Guido van Rossum54f22ed2000-02-04 15:10:34 +000030 """The parameter 'cmd' is the shell command to execute in a
31 sub-process. The 'capturestderr' flag, if true, specifies that
32 the object should capture standard error output of the child process.
33 The default is false. If the 'bufsize' parameter is specified, it
34 specifies the size of the I/O buffers to/from the child process."""
Fred Draked75e63a2000-09-28 19:07:53 +000035 _cleanup()
Guido van Rossum45e2fbc1998-03-26 21:13:24 +000036 p2cread, p2cwrite = os.pipe()
37 c2pread, c2pwrite = os.pipe()
38 if capturestderr:
39 errout, errin = os.pipe()
40 self.pid = os.fork()
41 if self.pid == 0:
42 # Child
Fred Draked75e63a2000-09-28 19:07:53 +000043 os.dup2(p2cread, 0)
44 os.dup2(c2pwrite, 1)
Guido van Rossum45e2fbc1998-03-26 21:13:24 +000045 if capturestderr:
Fred Draked75e63a2000-09-28 19:07:53 +000046 os.dup2(errin, 2)
47 self._run_child(cmd)
Guido van Rossum45e2fbc1998-03-26 21:13:24 +000048 os.close(p2cread)
49 self.tochild = os.fdopen(p2cwrite, 'w', bufsize)
50 os.close(c2pwrite)
51 self.fromchild = os.fdopen(c2pread, 'r', bufsize)
52 if capturestderr:
53 os.close(errin)
54 self.childerr = os.fdopen(errout, 'r', bufsize)
55 else:
56 self.childerr = None
Guido van Rossum45e2fbc1998-03-26 21:13:24 +000057 _active.append(self)
Guido van Rossum54f22ed2000-02-04 15:10:34 +000058
Fred Draked75e63a2000-09-28 19:07:53 +000059 def _run_child(self, cmd):
Martin v. Löwis95b057e2001-12-02 13:32:15 +000060 if isinstance(cmd, types.StringTypes):
Fred Draked75e63a2000-09-28 19:07:53 +000061 cmd = ['/bin/sh', '-c', cmd]
62 for i in range(3, MAXFD):
63 try:
64 os.close(i)
Skip Montanaro1c90d7a2002-03-24 20:48:26 +000065 except OSError:
Fred Draked75e63a2000-09-28 19:07:53 +000066 pass
67 try:
68 os.execvp(cmd[0], cmd)
69 finally:
70 os._exit(1)
71
Guido van Rossum0357d021997-08-11 03:27:24 +000072 def poll(self):
Guido van Rossum54f22ed2000-02-04 15:10:34 +000073 """Return the exit status of the child process if it has finished,
74 or -1 if it hasn't finished yet."""
Guido van Rossum45e2fbc1998-03-26 21:13:24 +000075 if self.sts < 0:
76 try:
77 pid, sts = os.waitpid(self.pid, os.WNOHANG)
78 if pid == self.pid:
79 self.sts = sts
80 _active.remove(self)
81 except os.error:
82 pass
83 return self.sts
Guido van Rossum54f22ed2000-02-04 15:10:34 +000084
Guido van Rossum0357d021997-08-11 03:27:24 +000085 def wait(self):
Guido van Rossum54f22ed2000-02-04 15:10:34 +000086 """Wait for and return the exit status of the child process."""
Guido van Rossum45e2fbc1998-03-26 21:13:24 +000087 pid, sts = os.waitpid(self.pid, 0)
88 if pid == self.pid:
89 self.sts = sts
90 _active.remove(self)
91 return self.sts
Guido van Rossumcaa9f231997-04-21 14:15:55 +000092
Fred Drake31f182e2000-08-28 17:20:05 +000093
Fred Draked75e63a2000-09-28 19:07:53 +000094class Popen4(Popen3):
95 childerr = None
96
97 def __init__(self, cmd, bufsize=-1):
98 _cleanup()
99 p2cread, p2cwrite = os.pipe()
100 c2pread, c2pwrite = os.pipe()
101 self.pid = os.fork()
102 if self.pid == 0:
103 # Child
104 os.dup2(p2cread, 0)
105 os.dup2(c2pwrite, 1)
106 os.dup2(c2pwrite, 2)
107 self._run_child(cmd)
108 os.close(p2cread)
109 self.tochild = os.fdopen(p2cwrite, 'w', bufsize)
110 os.close(c2pwrite)
111 self.fromchild = os.fdopen(c2pread, 'r', bufsize)
112 _active.append(self)
113
114
Andrew MacIntyre5cef5712002-02-24 05:32:32 +0000115if sys.platform[:3] == "win" or sys.platform == "os2emx":
Fred Draked75e63a2000-09-28 19:07:53 +0000116 # Some things don't make sense on non-Unix platforms.
Tim Petersd2152182000-10-03 23:07:13 +0000117 del Popen3, Popen4
Fred Draked75e63a2000-09-28 19:07:53 +0000118
119 def popen2(cmd, bufsize=-1, mode='t'):
Fredrik Lundh9ac81f62000-07-09 23:35:24 +0000120 """Execute the shell command 'cmd' in a sub-process. If 'bufsize' is
121 specified, it sets the buffer size for the I/O pipes. The file objects
122 (child_stdout, child_stdin) are returned."""
123 w, r = os.popen2(cmd, mode, bufsize)
124 return r, w
Guido van Rossumcaa9f231997-04-21 14:15:55 +0000125
Fred Draked75e63a2000-09-28 19:07:53 +0000126 def popen3(cmd, bufsize=-1, mode='t'):
Fredrik Lundh9ac81f62000-07-09 23:35:24 +0000127 """Execute the shell command 'cmd' in a sub-process. If 'bufsize' is
128 specified, it sets the buffer size for the I/O pipes. The file objects
129 (child_stdout, child_stdin, child_stderr) are returned."""
130 w, r, e = os.popen3(cmd, mode, bufsize)
131 return r, w, e
Fredrik Lundhbb7eeff2000-07-09 17:59:32 +0000132
Fred Draked75e63a2000-09-28 19:07:53 +0000133 def popen4(cmd, bufsize=-1, mode='t'):
Fredrik Lundh9ac81f62000-07-09 23:35:24 +0000134 """Execute the shell command 'cmd' in a sub-process. If 'bufsize' is
135 specified, it sets the buffer size for the I/O pipes. The file objects
136 (child_stdout_stderr, child_stdin) are returned."""
137 w, r = os.popen4(cmd, mode, bufsize)
138 return r, w
139else:
Fred Draked75e63a2000-09-28 19:07:53 +0000140 def popen2(cmd, bufsize=-1, mode='t'):
141 """Execute the shell command 'cmd' in a sub-process. If 'bufsize' is
142 specified, it sets the buffer size for the I/O pipes. The file objects
143 (child_stdout, child_stdin) are returned."""
144 inst = Popen3(cmd, 0, bufsize)
145 return inst.fromchild, inst.tochild
146
147 def popen3(cmd, bufsize=-1, mode='t'):
148 """Execute the shell command 'cmd' in a sub-process. If 'bufsize' is
149 specified, it sets the buffer size for the I/O pipes. The file objects
150 (child_stdout, child_stdin, child_stderr) are returned."""
151 inst = Popen3(cmd, 1, bufsize)
152 return inst.fromchild, inst.tochild, inst.childerr
153
154 def popen4(cmd, bufsize=-1, mode='t'):
155 """Execute the shell command 'cmd' in a sub-process. If 'bufsize' is
156 specified, it sets the buffer size for the I/O pipes. The file objects
157 (child_stdout_stderr, child_stdin) are returned."""
158 inst = Popen4(cmd, bufsize)
159 return inst.fromchild, inst.tochild
Guido van Rossum0357d021997-08-11 03:27:24 +0000160
Skip Montanaro352674d2001-02-07 23:14:30 +0000161 __all__.extend(["Popen3", "Popen4"])
Tim Peters658cba62001-02-09 20:06:00 +0000162
Guido van Rossum0357d021997-08-11 03:27:24 +0000163def _test():
Tim Peters84f28db2000-08-20 05:57:36 +0000164 cmd = "cat"
Tim Peters36208572000-09-01 20:38:55 +0000165 teststr = "ab cd\n"
Tim Peters84f28db2000-08-20 05:57:36 +0000166 if os.name == "nt":
167 cmd = "more"
Tim Peters36208572000-09-01 20:38:55 +0000168 # "more" doesn't act the same way across Windows flavors,
169 # sometimes adding an extra newline at the start or the
170 # end. So we strip whitespace off both ends for comparison.
171 expected = teststr.strip()
Guido van Rossum0357d021997-08-11 03:27:24 +0000172 print "testing popen2..."
Tim Peters84f28db2000-08-20 05:57:36 +0000173 r, w = popen2(cmd)
Guido van Rossum0357d021997-08-11 03:27:24 +0000174 w.write(teststr)
175 w.close()
Tim Peters36208572000-09-01 20:38:55 +0000176 got = r.read()
177 if got.strip() != expected:
178 raise ValueError("wrote %s read %s" % (`teststr`, `got`))
Guido van Rossum0357d021997-08-11 03:27:24 +0000179 print "testing popen3..."
Fredrik Lundhbb7eeff2000-07-09 17:59:32 +0000180 try:
Tim Peters84f28db2000-08-20 05:57:36 +0000181 r, w, e = popen3([cmd])
Fredrik Lundhbb7eeff2000-07-09 17:59:32 +0000182 except:
Tim Peters84f28db2000-08-20 05:57:36 +0000183 r, w, e = popen3(cmd)
Guido van Rossum0357d021997-08-11 03:27:24 +0000184 w.write(teststr)
185 w.close()
Tim Peters36208572000-09-01 20:38:55 +0000186 got = r.read()
187 if got.strip() != expected:
188 raise ValueError("wrote %s read %s" % (`teststr`, `got`))
189 got = e.read()
190 if got:
191 raise ValueError("unexected %s on stderr" % `got`)
Guido van Rossum068d5721999-04-20 12:27:31 +0000192 for inst in _active[:]:
193 inst.wait()
Tim Peters36208572000-09-01 20:38:55 +0000194 if _active:
195 raise ValueError("_active not empty")
Guido van Rossum0357d021997-08-11 03:27:24 +0000196 print "All OK"
197
198if __name__ == '__main__':
199 _test()