python 3.5 - subprocess.run все еще работает после того, как скрипт был прерван

Почему после того, как я завершаю сценарий Python с ctrl+c в то время как команда subprocess.run('knife ec2 server create...', shell=True, check=True) выполняется из этого сценария, элемент управления возвращается к сеансу терминала, но через несколько минут / сек команда оболочки снова появляется в сеансе терминала, а команда оболочки из subprocess.run Все еще работает?

Я думаю, что видел ту же проблему с os.system, например 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

Я пробовал также приведенный ниже код, но я получил ошибку:

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()

ошибка:

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

Есть ли простой способ запустить команду оболочки с python лайк Ruby с system()?

Спасибо

1 ответ

Модуль подпроцесса порождает новый процесс. когда вы отправляете сигнал CTRL+C в свой код Python, вы уже используете приложение Python, но подпроцесс все еще работает, и ваш код решает не ждать завершения процесса.

Попробуйте перехватить сигнал Ctrl+C в своем коде, а затем с помощью Popen завершите вызов, чтобы завершить подпроцесс перед существованием вашего приложения.

import shlex, subprocess
command_line = input()

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

p = subprocess.Popen(args) # Success!

Popen и подпроцессные документы

Вот документация API для вызова завершения:

Popen.Terminate

РЕДАКТИРОВАТЬ Вот пример демонстрационного кода для Python 2.7, раздел кода, который печатает strout, не применяется для ping, потому что он все равно будет выводить результат ping на терминал, но я поместил его там для справки.

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)
Другие вопросы по тегам