Home > Net >  Why using subprocess.check_output(shell=True) in python2.7 will cause hang?
Why using subprocess.check_output(shell=True) in python2.7 will cause hang?

Time:06-07

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. enter image description here

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'
  • Related