0001 """Spawn a command with pipes to its stdin, stdout, and optionally stderr. 0002 0003 The normal os.popen(cmd, mode) call spawns a shell command and provides a 0004 file interface to just the input or output of the process depending on 0005 whether mode is 'r' or 'w'. This module provides the functions popen2(cmd) 0006 and popen3(cmd) which return two or three pipes to the spawned command. 0007 """ 0008 0009 import os 0010 import sys 0011 0012 __all__ = ["popen2", "popen3", "popen4"] 0013 0014 try: 0015 MAXFD = os.sysconf('SC_OPEN_MAX') 0016 except (AttributeError, ValueError): 0017 MAXFD = 256 0018 0019 _active = [] 0020 0021 def _cleanup(): 0022 for inst in _active[:]: 0023 inst.poll() 0024 0025 class Popen3: 0026 """Class representing a child process. Normally instances are created 0027 by the factory functions popen2() and popen3().""" 0028 0029 sts = -1 # Child not completed yet 0030 0031 def __init__(self, cmd, capturestderr=False, bufsize=-1): 0032 """The parameter 'cmd' is the shell command to execute in a 0033 sub-process. On UNIX, 'cmd' may be a sequence, in which case arguments 0034 will be passed directly to the program without shell intervention (as 0035 with os.spawnv()). If 'cmd' is a string it will be passed to the shell 0036 (as with os.system()). The 'capturestderr' flag, if true, specifies 0037 that the object should capture standard error output of the child 0038 process. The default is false. If the 'bufsize' parameter is 0039 specified, it specifies the size of the I/O buffers to/from the child 0040 process.""" 0041 _cleanup() 0042 p2cread, p2cwrite = os.pipe() 0043 c2pread, c2pwrite = os.pipe() 0044 if capturestderr: 0045 errout, errin = os.pipe() 0046 self.pid = os.fork() 0047 if self.pid == 0: 0048 # Child 0049 os.dup2(p2cread, 0) 0050 os.dup2(c2pwrite, 1) 0051 if capturestderr: 0052 os.dup2(errin, 2) 0053 self._run_child(cmd) 0054 os.close(p2cread) 0055 self.tochild = os.fdopen(p2cwrite, 'w', bufsize) 0056 os.close(c2pwrite) 0057 self.fromchild = os.fdopen(c2pread, 'r', bufsize) 0058 if capturestderr: 0059 os.close(errin) 0060 self.childerr = os.fdopen(errout, 'r', bufsize) 0061 else: 0062 self.childerr = None 0063 _active.append(self) 0064 0065 def _run_child(self, cmd): 0066 if isinstance(cmd, basestring): 0067 cmd = ['/bin/sh', '-c', cmd] 0068 for i in range(3, MAXFD): 0069 try: 0070 os.close(i) 0071 except OSError: 0072 pass 0073 try: 0074 os.execvp(cmd[0], cmd) 0075 finally: 0076 os._exit(1) 0077 0078 def poll(self): 0079 """Return the exit status of the child process if it has finished, 0080 or -1 if it hasn't finished yet.""" 0081 if self.sts < 0: 0082 try: 0083 pid, sts = os.waitpid(self.pid, os.WNOHANG) 0084 if pid == self.pid: 0085 self.sts = sts 0086 _active.remove(self) 0087 except os.error: 0088 pass 0089 return self.sts 0090 0091 def wait(self): 0092 """Wait for and return the exit status of the child process.""" 0093 if self.sts < 0: 0094 pid, sts = os.waitpid(self.pid, 0) 0095 if pid == self.pid: 0096 self.sts = sts 0097 _active.remove(self) 0098 return self.sts 0099 0100 0101 class Popen4(Popen3): 0102 childerr = None 0103 0104 def __init__(self, cmd, bufsize=-1): 0105 _cleanup() 0106 p2cread, p2cwrite = os.pipe() 0107 c2pread, c2pwrite = os.pipe() 0108 self.pid = os.fork() 0109 if self.pid == 0: 0110 # Child 0111 os.dup2(p2cread, 0) 0112 os.dup2(c2pwrite, 1) 0113 os.dup2(c2pwrite, 2) 0114 self._run_child(cmd) 0115 os.close(p2cread) 0116 self.tochild = os.fdopen(p2cwrite, 'w', bufsize) 0117 os.close(c2pwrite) 0118 self.fromchild = os.fdopen(c2pread, 'r', bufsize) 0119 _active.append(self) 0120 0121 0122 if sys.platform[:3] == "win" or sys.platform == "os2emx": 0123 # Some things don't make sense on non-Unix platforms. 0124 del Popen3, Popen4 0125 0126 def popen2(cmd, bufsize=-1, mode='t'): 0127 """Execute the shell command 'cmd' in a sub-process. On UNIX, 'cmd' may 0128 be a sequence, in which case arguments will be passed directly to the 0129 program without shell intervention (as with os.spawnv()). If 'cmd' is a 0130 string it will be passed to the shell (as with os.system()). If 0131 'bufsize' is specified, it sets the buffer size for the I/O pipes. The 0132 file objects (child_stdout, child_stdin) are returned.""" 0133 w, r = os.popen2(cmd, mode, bufsize) 0134 return r, w 0135 0136 def popen3(cmd, bufsize=-1, mode='t'): 0137 """Execute the shell command 'cmd' in a sub-process. On UNIX, 'cmd' may 0138 be a sequence, in which case arguments will be passed directly to the 0139 program without shell intervention (as with os.spawnv()). If 'cmd' is a 0140 string it will be passed to the shell (as with os.system()). If 0141 'bufsize' is specified, it sets the buffer size for the I/O pipes. The 0142 file objects (child_stdout, child_stdin, child_stderr) are returned.""" 0143 w, r, e = os.popen3(cmd, mode, bufsize) 0144 return r, w, e 0145 0146 def popen4(cmd, bufsize=-1, mode='t'): 0147 """Execute the shell command 'cmd' in a sub-process. On UNIX, 'cmd' may 0148 be a sequence, in which case arguments will be passed directly to the 0149 program without shell intervention (as with os.spawnv()). If 'cmd' is a 0150 string it will be passed to the shell (as with os.system()). If 0151 'bufsize' is specified, it sets the buffer size for the I/O pipes. The 0152 file objects (child_stdout_stderr, child_stdin) are returned.""" 0153 w, r = os.popen4(cmd, mode, bufsize) 0154 return r, w 0155 else: 0156 def popen2(cmd, bufsize=-1, mode='t'): 0157 """Execute the shell command 'cmd' in a sub-process. On UNIX, 'cmd' may 0158 be a sequence, in which case arguments will be passed directly to the 0159 program without shell intervention (as with os.spawnv()). If 'cmd' is a 0160 string it will be passed to the shell (as with os.system()). If 0161 'bufsize' is specified, it sets the buffer size for the I/O pipes. The 0162 file objects (child_stdout, child_stdin) are returned.""" 0163 inst = Popen3(cmd, False, bufsize) 0164 return inst.fromchild, inst.tochild 0165 0166 def popen3(cmd, bufsize=-1, mode='t'): 0167 """Execute the shell command 'cmd' in a sub-process. On UNIX, 'cmd' may 0168 be a sequence, in which case arguments will be passed directly to the 0169 program without shell intervention (as with os.spawnv()). If 'cmd' is a 0170 string it will be passed to the shell (as with os.system()). If 0171 'bufsize' is specified, it sets the buffer size for the I/O pipes. The 0172 file objects (child_stdout, child_stdin, child_stderr) are returned.""" 0173 inst = Popen3(cmd, True, bufsize) 0174 return inst.fromchild, inst.tochild, inst.childerr 0175 0176 def popen4(cmd, bufsize=-1, mode='t'): 0177 """Execute the shell command 'cmd' in a sub-process. On UNIX, 'cmd' may 0178 be a sequence, in which case arguments will be passed directly to the 0179 program without shell intervention (as with os.spawnv()). If 'cmd' is a 0180 string it will be passed to the shell (as with os.system()). If 0181 'bufsize' is specified, it sets the buffer size for the I/O pipes. The 0182 file objects (child_stdout_stderr, child_stdin) are returned.""" 0183 inst = Popen4(cmd, bufsize) 0184 return inst.fromchild, inst.tochild 0185 0186 __all__.extend(["Popen3", "Popen4"]) 0187 0188 def _test(): 0189 cmd = "cat" 0190 teststr = "ab cd\n" 0191 if os.name == "nt": 0192 cmd = "more" 0193 # "more" doesn't act the same way across Windows flavors, 0194 # sometimes adding an extra newline at the start or the 0195 # end. So we strip whitespace off both ends for comparison. 0196 expected = teststr.strip() 0197 print "testing popen2..." 0198 r, w = popen2(cmd) 0199 w.write(teststr) 0200 w.close() 0201 got = r.read() 0202 if got.strip() != expected: 0203 raise ValueError("wrote %r read %r" % (teststr, got)) 0204 print "testing popen3..." 0205 try: 0206 r, w, e = popen3([cmd]) 0207 except: 0208 r, w, e = popen3(cmd) 0209 w.write(teststr) 0210 w.close() 0211 got = r.read() 0212 if got.strip() != expected: 0213 raise ValueError("wrote %r read %r" % (teststr, got)) 0214 got = e.read() 0215 if got: 0216 raise ValueError("unexected %r on stderr" % (got,)) 0217 for inst in _active[:]: 0218 inst.wait() 0219 if _active: 0220 raise ValueError("_active not empty") 0221 print "All OK" 0222 0223 if __name__ == '__main__': 0224 _test() 0225
Generated by PyXR 0.9.4