blob: eb8fb9ad1fcdf0b6a0a13ac5e644575aaf4b4163 [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
11import string
12
Guido van Rossum45e2fbc1998-03-26 21:13:24 +000013MAXFD = 256 # Max number of file descriptors (os.getdtablesize()???)
Guido van Rossum9a22de11995-01-12 12:29:47 +000014
Guido van Rossum0357d021997-08-11 03:27:24 +000015_active = []
16
17def _cleanup():
18 for inst in _active[:]:
Guido van Rossum45e2fbc1998-03-26 21:13:24 +000019 inst.poll()
Guido van Rossum0357d021997-08-11 03:27:24 +000020
21class Popen3:
Guido van Rossum54f22ed2000-02-04 15:10:34 +000022 """Class representing a child process. Normally instances are created
23 by the factory functions popen2() and popen3()."""
24
Guido van Rossumda286661997-09-29 04:04:39 +000025 def __init__(self, cmd, capturestderr=0, bufsize=-1):
Guido van Rossum54f22ed2000-02-04 15:10:34 +000026 """The parameter 'cmd' is the shell command to execute in a
27 sub-process. The 'capturestderr' flag, if true, specifies that
28 the object should capture standard error output of the child process.
29 The default is false. If the 'bufsize' parameter is specified, it
30 specifies the size of the I/O buffers to/from the child process."""
Guido van Rossum45e2fbc1998-03-26 21:13:24 +000031 if type(cmd) == type(''):
32 cmd = ['/bin/sh', '-c', cmd]
33 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
40 os.close(0)
41 os.close(1)
42 if os.dup(p2cread) <> 0:
43 sys.stderr.write('popen2: bad read dup\n')
44 if os.dup(c2pwrite) <> 1:
45 sys.stderr.write('popen2: bad write dup\n')
46 if capturestderr:
47 os.close(2)
48 if os.dup(errin) <> 2: pass
49 for i in range(3, MAXFD):
50 try:
51 os.close(i)
52 except: pass
53 try:
54 os.execvp(cmd[0], cmd)
55 finally:
56 os._exit(1)
57 # Shouldn't come here, I guess
58 os._exit(1)
59 os.close(p2cread)
60 self.tochild = os.fdopen(p2cwrite, 'w', bufsize)
61 os.close(c2pwrite)
62 self.fromchild = os.fdopen(c2pread, 'r', bufsize)
63 if capturestderr:
64 os.close(errin)
65 self.childerr = os.fdopen(errout, 'r', bufsize)
66 else:
67 self.childerr = None
68 self.sts = -1 # Child not completed yet
69 _active.append(self)
Guido van Rossum54f22ed2000-02-04 15:10:34 +000070
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
Guido van Rossumda286661997-09-29 04:04:39 +000092def popen2(cmd, bufsize=-1):
Guido van Rossum54f22ed2000-02-04 15:10:34 +000093 """Execute the shell command 'cmd' in a sub-process. If 'bufsize' is
94 specified, it sets the buffer size for the I/O pipes. The file objects
95 (child_stdout, child_stdin) are returned."""
Guido van Rossum0357d021997-08-11 03:27:24 +000096 _cleanup()
Guido van Rossumda286661997-09-29 04:04:39 +000097 inst = Popen3(cmd, 0, bufsize)
Guido van Rossum0357d021997-08-11 03:27:24 +000098 return inst.fromchild, inst.tochild
Guido van Rossumcaa9f231997-04-21 14:15:55 +000099
Guido van Rossumda286661997-09-29 04:04:39 +0000100def popen3(cmd, bufsize=-1):
Guido van Rossum54f22ed2000-02-04 15:10:34 +0000101 """Execute the shell command 'cmd' in a sub-process. If 'bufsize' is
102 specified, it sets the buffer size for the I/O pipes. The file objects
103 (child_stdout, child_stdin, child_stderr) are returned."""
Guido van Rossum0357d021997-08-11 03:27:24 +0000104 _cleanup()
Guido van Rossumda286661997-09-29 04:04:39 +0000105 inst = Popen3(cmd, 1, bufsize)
Guido van Rossum0357d021997-08-11 03:27:24 +0000106 return inst.fromchild, inst.tochild, inst.childerr
107
108def _test():
109 teststr = "abc\n"
110 print "testing popen2..."
111 r, w = popen2('cat')
112 w.write(teststr)
113 w.close()
114 assert r.read() == teststr
115 print "testing popen3..."
Guido van Rossum6dd48681997-09-18 20:00:39 +0000116 r, w, e = popen3(['cat'])
Guido van Rossum0357d021997-08-11 03:27:24 +0000117 w.write(teststr)
118 w.close()
119 assert r.read() == teststr
120 assert e.read() == ""
Guido van Rossum068d5721999-04-20 12:27:31 +0000121 for inst in _active[:]:
122 inst.wait()
Guido van Rossum0357d021997-08-11 03:27:24 +0000123 assert not _active
124 print "All OK"
125
126if __name__ == '__main__':
127 _test()