blob: 8a176412f305e9efc25f3b27dcfe27fe73fdfe1b [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
Skip Montanaro57fd45e2002-03-12 19:48:03 +000012__all__ = ["popen2", "popen3", "popen4"]
Skip Montanaro352674d2001-02-07 23:14:30 +000013
Guido van Rossum45e2fbc1998-03-26 21:13:24 +000014MAXFD = 256 # Max number of file descriptors (os.getdtablesize()???)
Guido van Rossum9a22de11995-01-12 12:29:47 +000015
Guido van Rossum0357d021997-08-11 03:27:24 +000016_active = []
17
18def _cleanup():
19 for inst in _active[:]:
Guido van Rossum45e2fbc1998-03-26 21:13:24 +000020 inst.poll()
Guido van Rossum0357d021997-08-11 03:27:24 +000021
22class Popen3:
Guido van Rossum54f22ed2000-02-04 15:10:34 +000023 """Class representing a child process. Normally instances are created
24 by the factory functions popen2() and popen3()."""
25
Fred Draked75e63a2000-09-28 19:07:53 +000026 sts = -1 # Child not completed yet
27
Guido van Rossumda286661997-09-29 04:04:39 +000028 def __init__(self, cmd, capturestderr=0, bufsize=-1):
Guido van Rossum54f22ed2000-02-04 15:10:34 +000029 """The parameter 'cmd' is the shell command to execute in a
30 sub-process. The 'capturestderr' flag, if true, specifies that
31 the object should capture standard error output of the child process.
32 The default is false. If the 'bufsize' parameter is specified, it
33 specifies the size of the I/O buffers to/from the child process."""
Fred Draked75e63a2000-09-28 19:07:53 +000034 _cleanup()
Guido van Rossum45e2fbc1998-03-26 21:13:24 +000035 p2cread, p2cwrite = os.pipe()
36 c2pread, c2pwrite = os.pipe()
37 if capturestderr:
38 errout, errin = os.pipe()
39 self.pid = os.fork()
40 if self.pid == 0:
41 # Child
Fred Draked75e63a2000-09-28 19:07:53 +000042 os.dup2(p2cread, 0)
43 os.dup2(c2pwrite, 1)
Guido van Rossum45e2fbc1998-03-26 21:13:24 +000044 if capturestderr:
Fred Draked75e63a2000-09-28 19:07:53 +000045 os.dup2(errin, 2)
46 self._run_child(cmd)
Guido van Rossum45e2fbc1998-03-26 21:13:24 +000047 os.close(p2cread)
48 self.tochild = os.fdopen(p2cwrite, 'w', bufsize)
49 os.close(c2pwrite)
50 self.fromchild = os.fdopen(c2pread, 'r', bufsize)
51 if capturestderr:
52 os.close(errin)
53 self.childerr = os.fdopen(errout, 'r', bufsize)
54 else:
55 self.childerr = None
Guido van Rossum45e2fbc1998-03-26 21:13:24 +000056 _active.append(self)
Guido van Rossum54f22ed2000-02-04 15:10:34 +000057
Fred Draked75e63a2000-09-28 19:07:53 +000058 def _run_child(self, cmd):
Walter Dörwald65230a22002-06-03 15:58:32 +000059 if isinstance(cmd, basestring):
Fred Draked75e63a2000-09-28 19:07:53 +000060 cmd = ['/bin/sh', '-c', cmd]
61 for i in range(3, MAXFD):
62 try:
63 os.close(i)
Skip Montanaro1c90d7a2002-03-24 20:48:26 +000064 except OSError:
Fred Draked75e63a2000-09-28 19:07:53 +000065 pass
66 try:
67 os.execvp(cmd[0], cmd)
68 finally:
69 os._exit(1)
70
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 Rossum3800ef72003-06-02 19:12:01 +000086 if self.sts < 0:
87 pid, sts = os.waitpid(self.pid, 0)
88 if pid == self.pid:
89 self.sts = sts
90 _active.remove(self)
Guido van Rossum45e2fbc1998-03-26 21:13:24 +000091 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()