I am writing a web application that will execute a command on the local Windows server and need to display the output. The Popen() call in my code executes fine on the Python interpreter but gives a nasty error when executed via IIS. Thanks!!!!
Error text:
Traceback (most recent call last):
File "C:\pythonapps\mystdout.py", line 9, in print Popen('ipconfig', shell=True, stdout=PIPE).communicate()[0]
File "C:\Python27\lib\subprocess.py", line 672, in init errread, errwrite) = self._get_handles(stdin, stdout, stderr)
File "C:\Python27\lib\subprocess.py", line 774, in _get_handles p2cread = _subprocess.GetStdHandle(_subprocess.STD_INPUT_HANDLE)
WindowsError: [Error 6] The handle is invalid
from subprocess import *
print "Content-type:text/html\r\n\r\n"
print "<html>"
print "<head>"
print "<title>FSPCT app</title>"
print "</head>"
print "<body>"
print Popen('ipconfig', shell=True, stdout=PIPE).communicate()[0]
print "</body>"
print "</html>"
It looks like the IIS server doesn't have a valid stdin file handle (not all that surprising, as it's a server process). The subprocess
module is trying to copy that stdin file handle... and failing.
To fix this, call Popen
for the subprocess you're executing with the stdin file handle (and maybe stderr too for good measure) bound to the NUL file. (os.devnull is the portable way of referring to that file in Python 2.7.) Said NUL file (or /dev/null under Unix) simply discards everything written to it, and returns end-of-file immediately when read from. Perfect for this.
Try modifying your code like this:
import os
...
with open(os.devnull, 'r+') as nul:
print Popen('ipconfig', shell=True, stdin=nul, stdout=PIPE, stderr=nul).communicate()[0]
(In the upcoming Python 3.3, you can now pass subprocess.DEVNULL to the stdin, stdout or stderr arguments of Popen to do the same thing more concisely.)
communicate()
has the exact same behavior: Popen('cat', shell=True, stdin=PIPE, stdout=PIPE).communicate()[0]
(on a system with cat
present) will exit immediately, exactly as if you had passed /dev/null
to stdin. As such, opening and passing devnull serves no real purpose but complicating the code - lunixbochs 2012-04-09 18:40
The default subprocess.Popen() value for stdin is None
, which passes stdin from the parent process.
To use an internal stdin, just pass stdin=PIPE
with your Popen()
call.
print Popen('ipconfig', shell=True, stdin=PIPE, stdout=PIPE).communicate()[0]
subprocess
will have the same effect when youcommunicate()
orcommunicate('')
after specifyingstdin=PIPE
lunixbochs 2012-04-05 21:33