source: python/trunk/Lib/popen2.py@ 610

Last change on this file since 610 was 603, checked in by dmik, 10 years ago

python: Use configured SHELL in subprocess module.

Use the shell that was configured when building python whe
supbropcess.Popen(shell=True) is requested instead of the
hardcoded '/bin/sh' value which might be not there.

Closes #141.

  • Property svn:eol-style set to native
File size: 8.3 KB
Line 
1"""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
9import os
10import sys
11import warnings
12warnings.warn("The popen2 module is deprecated. Use the subprocess module.",
13 DeprecationWarning, stacklevel=2)
14
15import sysconfig
16SHELL = sysconfig.get_config_var('SHELL') or '/bin/sh'
17
18__all__ = ["popen2", "popen3", "popen4"]
19
20try:
21 MAXFD = os.sysconf('SC_OPEN_MAX')
22except (AttributeError, ValueError):
23 MAXFD = 256
24
25_active = []
26
27def _cleanup():
28 for inst in _active[:]:
29 if inst.poll(_deadstate=sys.maxint) >= 0:
30 try:
31 _active.remove(inst)
32 except ValueError:
33 # This can happen if two threads create a new Popen instance.
34 # It's harmless that it was already removed, so ignore.
35 pass
36
37class Popen3:
38 """Class representing a child process. Normally, instances are created
39 internally by the functions popen2() and popen3()."""
40
41 sts = -1 # Child not completed yet
42
43 def __init__(self, cmd, capturestderr=False, bufsize=-1):
44 """The parameter 'cmd' is the shell command to execute in a
45 sub-process. On UNIX, 'cmd' may be a sequence, in which case arguments
46 will be passed directly to the program without shell intervention (as
47 with os.spawnv()). If 'cmd' is a string it will be passed to the shell
48 (as with os.system()). The 'capturestderr' flag, if true, specifies
49 that the object should capture standard error output of the child
50 process. The default is false. If the 'bufsize' parameter is
51 specified, it specifies the size of the I/O buffers to/from the child
52 process."""
53 _cleanup()
54 self.cmd = cmd
55 p2cread, p2cwrite = os.pipe()
56 c2pread, c2pwrite = os.pipe()
57 if capturestderr:
58 errout, errin = os.pipe()
59 self.pid = os.fork()
60 if self.pid == 0:
61 # Child
62 os.dup2(p2cread, 0)
63 os.dup2(c2pwrite, 1)
64 if capturestderr:
65 os.dup2(errin, 2)
66 self._run_child(cmd)
67 os.close(p2cread)
68 self.tochild = os.fdopen(p2cwrite, 'w', bufsize)
69 os.close(c2pwrite)
70 self.fromchild = os.fdopen(c2pread, 'r', bufsize)
71 if capturestderr:
72 os.close(errin)
73 self.childerr = os.fdopen(errout, 'r', bufsize)
74 else:
75 self.childerr = None
76
77 def __del__(self):
78 # In case the child hasn't been waited on, check if it's done.
79 self.poll(_deadstate=sys.maxint)
80 if self.sts < 0:
81 if _active is not None:
82 # Child is still running, keep us alive until we can wait on it.
83 _active.append(self)
84
85 def _run_child(self, cmd):
86 if isinstance(cmd, basestring):
87 cmd = [SHELL, '-c', cmd]
88 os.closerange(3, MAXFD)
89 try:
90 os.execvp(cmd[0], cmd)
91 finally:
92 os._exit(1)
93
94 def poll(self, _deadstate=None):
95 """Return the exit status of the child process if it has finished,
96 or -1 if it hasn't finished yet."""
97 if self.sts < 0:
98 try:
99 pid, sts = os.waitpid(self.pid, os.WNOHANG)
100 # pid will be 0 if self.pid hasn't terminated
101 if pid == self.pid:
102 self.sts = sts
103 except os.error:
104 if _deadstate is not None:
105 self.sts = _deadstate
106 return self.sts
107
108 def wait(self):
109 """Wait for and return the exit status of the child process."""
110 if self.sts < 0:
111 pid, sts = os.waitpid(self.pid, 0)
112 # This used to be a test, but it is believed to be
113 # always true, so I changed it to an assertion - mvl
114 assert pid == self.pid
115 self.sts = sts
116 return self.sts
117
118
119class Popen4(Popen3):
120 childerr = None
121
122 def __init__(self, cmd, bufsize=-1):
123 _cleanup()
124 self.cmd = cmd
125 p2cread, p2cwrite = os.pipe()
126 c2pread, c2pwrite = os.pipe()
127 self.pid = os.fork()
128 if self.pid == 0:
129 # Child
130 os.dup2(p2cread, 0)
131 os.dup2(c2pwrite, 1)
132 os.dup2(c2pwrite, 2)
133 self._run_child(cmd)
134 os.close(p2cread)
135 self.tochild = os.fdopen(p2cwrite, 'w', bufsize)
136 os.close(c2pwrite)
137 self.fromchild = os.fdopen(c2pread, 'r', bufsize)
138
139
140if sys.platform[:3] == "win" or sys.platform == "os2emx" or sys.platform == "os2knix":
141 # Some things don't make sense on non-Unix platforms.
142 del Popen3, Popen4
143
144 def popen2(cmd, bufsize=-1, mode='t'):
145 """Execute the shell command 'cmd' in a sub-process. On UNIX, 'cmd' may
146 be a sequence, in which case arguments will be passed directly to the
147 program without shell intervention (as with os.spawnv()). If 'cmd' is a
148 string it will be passed to the shell (as with os.system()). If
149 'bufsize' is specified, it sets the buffer size for the I/O pipes. The
150 file objects (child_stdout, child_stdin) are returned."""
151 w, r = os.popen2(cmd, mode, bufsize)
152 return r, w
153
154 def popen3(cmd, bufsize=-1, mode='t'):
155 """Execute the shell command 'cmd' in a sub-process. On UNIX, 'cmd' may
156 be a sequence, in which case arguments will be passed directly to the
157 program without shell intervention (as with os.spawnv()). If 'cmd' is a
158 string it will be passed to the shell (as with os.system()). If
159 'bufsize' is specified, it sets the buffer size for the I/O pipes. The
160 file objects (child_stdout, child_stdin, child_stderr) are returned."""
161 w, r, e = os.popen3(cmd, mode, bufsize)
162 return r, w, e
163
164 def popen4(cmd, bufsize=-1, mode='t'):
165 """Execute the shell command 'cmd' in a sub-process. On UNIX, 'cmd' may
166 be a sequence, in which case arguments will be passed directly to the
167 program without shell intervention (as with os.spawnv()). If 'cmd' is a
168 string it will be passed to the shell (as with os.system()). If
169 'bufsize' is specified, it sets the buffer size for the I/O pipes. The
170 file objects (child_stdout_stderr, child_stdin) are returned."""
171 w, r = os.popen4(cmd, mode, bufsize)
172 return r, w
173else:
174 def popen2(cmd, bufsize=-1, mode='t'):
175 """Execute the shell command 'cmd' in a sub-process. On UNIX, 'cmd' may
176 be a sequence, in which case arguments will be passed directly to the
177 program without shell intervention (as with os.spawnv()). If 'cmd' is a
178 string it will be passed to the shell (as with os.system()). If
179 'bufsize' is specified, it sets the buffer size for the I/O pipes. The
180 file objects (child_stdout, child_stdin) are returned."""
181 inst = Popen3(cmd, False, bufsize)
182 return inst.fromchild, inst.tochild
183
184 def popen3(cmd, bufsize=-1, mode='t'):
185 """Execute the shell command 'cmd' in a sub-process. On UNIX, 'cmd' may
186 be a sequence, in which case arguments will be passed directly to the
187 program without shell intervention (as with os.spawnv()). If 'cmd' is a
188 string it will be passed to the shell (as with os.system()). If
189 'bufsize' is specified, it sets the buffer size for the I/O pipes. The
190 file objects (child_stdout, child_stdin, child_stderr) are returned."""
191 inst = Popen3(cmd, True, bufsize)
192 return inst.fromchild, inst.tochild, inst.childerr
193
194 def popen4(cmd, bufsize=-1, mode='t'):
195 """Execute the shell command 'cmd' in a sub-process. On UNIX, 'cmd' may
196 be a sequence, in which case arguments will be passed directly to the
197 program without shell intervention (as with os.spawnv()). If 'cmd' is a
198 string it will be passed to the shell (as with os.system()). If
199 'bufsize' is specified, it sets the buffer size for the I/O pipes. The
200 file objects (child_stdout_stderr, child_stdin) are returned."""
201 inst = Popen4(cmd, bufsize)
202 return inst.fromchild, inst.tochild
203
204 __all__.extend(["Popen3", "Popen4"])
Note: See TracBrowser for help on using the repository browser.