blob: 8b1af7620ae2064a3ea9cc7d04945518d3b2ee63 [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 Montanaro352674d2001-02-07 23:14:30 +000012__all__ = ["popen2", "popen3", "popen4"]
13
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):
59 if type(cmd) == type(''):
60 cmd = ['/bin/sh', '-c', cmd]
61 for i in range(3, MAXFD):
62 try:
63 os.close(i)
64 except:
65 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 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
Fred Draked75e63a2000-09-28 19:07:53 +000093class Popen4(Popen3):
94 childerr = None
95
96 def __init__(self, cmd, bufsize=-1):
97 _cleanup()
98 p2cread, p2cwrite = os.pipe()
99 c2pread, c2pwrite = os.pipe()
100 self.pid = os.fork()
101 if self.pid == 0:
102 # Child
103 os.dup2(p2cread, 0)
104 os.dup2(c2pwrite, 1)
105 os.dup2(c2pwrite, 2)
106 self._run_child(cmd)
107 os.close(p2cread)
108 self.tochild = os.fdopen(p2cwrite, 'w', bufsize)
109 os.close(c2pwrite)
110 self.fromchild = os.fdopen(c2pread, 'r', bufsize)
111 _active.append(self)
112
113
Fred Drake31f182e2000-08-28 17:20:05 +0000114if sys.platform[:3] == "win":
Fred Draked75e63a2000-09-28 19:07:53 +0000115 # Some things don't make sense on non-Unix platforms.
Tim Petersd2152182000-10-03 23:07:13 +0000116 del Popen3, Popen4
Fred Draked75e63a2000-09-28 19:07:53 +0000117
118 def popen2(cmd, bufsize=-1, mode='t'):
Fredrik Lundh9ac81f62000-07-09 23:35:24 +0000119 """Execute the shell command 'cmd' in a sub-process. If 'bufsize' is
120 specified, it sets the buffer size for the I/O pipes. The file objects
121 (child_stdout, child_stdin) are returned."""
122 w, r = os.popen2(cmd, mode, bufsize)
123 return r, w
Guido van Rossumcaa9f231997-04-21 14:15:55 +0000124
Fred Draked75e63a2000-09-28 19:07:53 +0000125 def popen3(cmd, bufsize=-1, mode='t'):
Fredrik Lundh9ac81f62000-07-09 23:35:24 +0000126 """Execute the shell command 'cmd' in a sub-process. If 'bufsize' is
127 specified, it sets the buffer size for the I/O pipes. The file objects
128 (child_stdout, child_stdin, child_stderr) are returned."""
129 w, r, e = os.popen3(cmd, mode, bufsize)
130 return r, w, e
Fredrik Lundhbb7eeff2000-07-09 17:59:32 +0000131
Fred Draked75e63a2000-09-28 19:07:53 +0000132 def popen4(cmd, bufsize=-1, mode='t'):
Fredrik Lundh9ac81f62000-07-09 23:35:24 +0000133 """Execute the shell command 'cmd' in a sub-process. If 'bufsize' is
134 specified, it sets the buffer size for the I/O pipes. The file objects
135 (child_stdout_stderr, child_stdin) are returned."""
136 w, r = os.popen4(cmd, mode, bufsize)
137 return r, w
138else:
Fred Draked75e63a2000-09-28 19:07:53 +0000139 def popen2(cmd, bufsize=-1, mode='t'):
140 """Execute the shell command 'cmd' in a sub-process. If 'bufsize' is
141 specified, it sets the buffer size for the I/O pipes. The file objects
142 (child_stdout, child_stdin) are returned."""
143 inst = Popen3(cmd, 0, bufsize)
144 return inst.fromchild, inst.tochild
145
146 def popen3(cmd, bufsize=-1, mode='t'):
147 """Execute the shell command 'cmd' in a sub-process. If 'bufsize' is
148 specified, it sets the buffer size for the I/O pipes. The file objects
149 (child_stdout, child_stdin, child_stderr) are returned."""
150 inst = Popen3(cmd, 1, bufsize)
151 return inst.fromchild, inst.tochild, inst.childerr
152
153 def popen4(cmd, bufsize=-1, mode='t'):
154 """Execute the shell command 'cmd' in a sub-process. If 'bufsize' is
155 specified, it sets the buffer size for the I/O pipes. The file objects
156 (child_stdout_stderr, child_stdin) are returned."""
157 inst = Popen4(cmd, bufsize)
158 return inst.fromchild, inst.tochild
Guido van Rossum0357d021997-08-11 03:27:24 +0000159
Skip Montanaro352674d2001-02-07 23:14:30 +0000160 __all__.extend(["Popen3", "Popen4"])
Tim Peters658cba62001-02-09 20:06:00 +0000161
Guido van Rossum0357d021997-08-11 03:27:24 +0000162def _test():
Tim Peters84f28db2000-08-20 05:57:36 +0000163 cmd = "cat"
Tim Peters36208572000-09-01 20:38:55 +0000164 teststr = "ab cd\n"
Tim Peters84f28db2000-08-20 05:57:36 +0000165 if os.name == "nt":
166 cmd = "more"
Tim Peters36208572000-09-01 20:38:55 +0000167 # "more" doesn't act the same way across Windows flavors,
168 # sometimes adding an extra newline at the start or the
169 # end. So we strip whitespace off both ends for comparison.
170 expected = teststr.strip()
Guido van Rossum0357d021997-08-11 03:27:24 +0000171 print "testing popen2..."
Tim Peters84f28db2000-08-20 05:57:36 +0000172 r, w = popen2(cmd)
Guido van Rossum0357d021997-08-11 03:27:24 +0000173 w.write(teststr)
174 w.close()
Tim Peters36208572000-09-01 20:38:55 +0000175 got = r.read()
176 if got.strip() != expected:
177 raise ValueError("wrote %s read %s" % (`teststr`, `got`))
Guido van Rossum0357d021997-08-11 03:27:24 +0000178 print "testing popen3..."
Fredrik Lundhbb7eeff2000-07-09 17:59:32 +0000179 try:
Tim Peters84f28db2000-08-20 05:57:36 +0000180 r, w, e = popen3([cmd])
Fredrik Lundhbb7eeff2000-07-09 17:59:32 +0000181 except:
Tim Peters84f28db2000-08-20 05:57:36 +0000182 r, w, e = popen3(cmd)
Guido van Rossum0357d021997-08-11 03:27:24 +0000183 w.write(teststr)
184 w.close()
Tim Peters36208572000-09-01 20:38:55 +0000185 got = r.read()
186 if got.strip() != expected:
187 raise ValueError("wrote %s read %s" % (`teststr`, `got`))
188 got = e.read()
189 if got:
190 raise ValueError("unexected %s on stderr" % `got`)
Guido van Rossum068d5721999-04-20 12:27:31 +0000191 for inst in _active[:]:
192 inst.wait()
Tim Peters36208572000-09-01 20:38:55 +0000193 if _active:
194 raise ValueError("_active not empty")
Guido van Rossum0357d021997-08-11 03:27:24 +0000195 print "All OK"
196
197if __name__ == '__main__':
198 _test()