Code
in b.py
# b.py
import subprocess
from sys import stdout
cmd = ['python2.7','a.py']
try:
subprocess.check_output(cmd, stderr=subprocess.STDOUT, shell=True)
except subprocess.CalledProcessError as e:
print 'cmd:', e.cmd, 'end'
print 'output:', e.output,'end'
print 'returncode:', e.returncode, 'end'
print 'ok'
in a.py
# a.py
import sys
print 'a.py'
sys.stderr.write('stderr\n')
sys.stdout.write('stdout\n')
exit(-1)
What I do
after I call python2.7 b.py
, it stopped, as if waiting for input.
after I type ctrl-c
, the traceback is:
/home/liweiming/app/test〉python2.7 b.py 06/07/2022 11:25:07 AM
^CTraceback (most recent call last):
File "b.py", line 10, in <module>
subprocess.check_output(cmd, stderr=subprocess.STDOUT, shell=True)
File "/usr/lib/python2.7/subprocess.py", line 217, in check_output
output, unused_err = process.communicate()
File "/usr/lib/python2.7/subprocess.py", line 475, in communicate
stdout = _eintr_retry_call(self.stdout.read)
File "/usr/lib/python2.7/subprocess.py", line 125, in _eintr_retry_call
return func(*args)
KeyboardInterrupt
But if I use subprocess.check_output(shell=False)
, the program is well.
CodePudding user response:
with shell=True
the command becomes ['sh', '-c', 'python2.7', 'a.py']
-- this passes a.py
as an argument to sh
(which is roughly ignored -- it's set as $0
in the interactive script but it doesn't matter because that script is just python2.7
) -- this then runs python2.7
since that command is still attached to the terminal, it will wait for input (as the interactive interpreter does) -- try for instance typing 1 1<enter><^D>
and you'll get output back (from the interactive python2.7
itself)
definitely a weird behaviour, I would've rather hoped that command being a list shell=True would raise a TypeError (requiring the command to be a string) -- but alas
here's an example of the shell=True
behaviour passing positional arguments to the shell string:
>>> subprocess.check_output(['echo $0 $1', 'hello', 'world'], shell=True)
b'hello world\n'