Berlin
Berlin

Reputation: 1464

python 3.5 - subprocess.run still running after the script was terminated

Why after I terminate a python script with ctrl+c while the command subprocess.run('knife ec2 server create...', shell=True, check=True) is running from this script, the control returns to the terminal session but after a few min/sec the shell command reappears in the terminal session and the shell command from subprocess.run still running?

I think I saw the same issue with os.system, for example os.system('ping 8.8.8.8') .

^C

Waiting for EC2 to create the instance.....^CTraceback (most recent call last):
  File "t.py", line 177, in <module>
    subprocess.run(command, shell=True, check=True)
  File "/usr/lib/python3.5/subprocess.py", line 695, in run
    stdout, stderr = process.communicate(input, timeout=timeout)
  File "/usr/lib/python3.5/subprocess.py", line 1064, in communicate
    self.wait()
  File "/usr/lib/python3.5/subprocess.py", line 1658, in wait
    (pid, sts) = self._try_wait(0)
  File "/usr/lib/python3.5/subprocess.py", line 1608, in _try_wait
    (pid, sts) = os.waitpid(self.pid, wait_flags)
KeyboardInterrupt
$ ..............................................................................done

SSH Target Address: ec2()
Doing old-style registration with the validation key at /etc/chef/validation.pem...
Delete your validation key in order to use your user credentials instead

I tried also the below code but I got an error:

command = ('knife ec2 server create -N ' + fullname + ' -f ' + instance_type + ' -i ' + pem_file)...

p = subprocess.Popen(command, shell=True, stderr=subprocess.PIPE)
while True:
    out = p.stderr.read(1)
    if out == '' and p.poll() != None:
        break
    if out != '':
        sys.stdout.write(out)
        sys.stdout.flush()

error:

`sys.stdout.write(out) TypeError: write() argument must be str, not bytes'

Is there a simple way to run a shell command with python like Ruby with system() ?

Thanks

Upvotes: 1

Views: 3682

Answers (1)

Armen Babakanian
Armen Babakanian

Reputation: 2325

the subprocess module spawns a new process. when you send the CTRL+C signal to your python code, you are existing your python application but the subprocess is still running and your code decides not to wait for the process to finish.

Try catching the Ctrl+C signal in your code, and then use Popen terminate call to end the subprocess before existing your application.

import shlex, subprocess
command_line = input()

args = shlex.split(command_line)
print(args)

p = subprocess.Popen(args) # Success!

Popen and subprocess docs

Here is the API doc for the terminate call:

Popen.Terminate

EDIT Here is sample demo code for python 2.7, the section of the code that prints strout doesn't apply for ping, because it will still output the ping result to the terminal, but I placed it there for reference.

import subprocess
import signal
import sys

command = 'ping {0}'.format('8.8.8.8')
p = subprocess.Popen(command, shell=True, stderr=subprocess.PIPE)

# callback for the Ctrl+C signal
def signal_handler(signal, frame):
    print("CTRL+C received")
    p.kill() # or terminate
    p.wait()
    sys.exit(0)    

# register signal with the callback
signal.signal(signal.SIGINT, signal_handler)

# white subprocess hasn't finished
while p.poll() is None:
    out = p.communicate()
    print(out.stdoutdata)

Upvotes: 2

Related Questions