Отправить Ctrl-C для удаленных процессов, запущенных через подпроцесс.Popen и ssh

Как отправить Ctrl-C нескольким процессам ssh -t в объектах Popen() ?

У меня есть код Python, который запускает скрипт на удаленном хосте:

 # kickoff.py # i call 'ssh' w/ the '-t' flag so that when i press 'ctrl-c', it get's # sent to the script on the remote host. otherwise 'ctrol-c' would just # kill things on this end, and the script would still be running on the # remote server a = subprocess.Popen(['ssh', '-t', 'remote-host', './script.sh', 'a']) a.communicate() 

Это отлично работает, но мне нужно запустить несколько сценариев на удаленном хосте:

 # kickoff.py a = subprocess.Popen(['ssh', '-t', 'remote-host', './script.sh', 'a']) b = subprocess.Popen(['ssh', '-t', 'remote-host', './script.sh', 'b']) a.communicate() b.communicate() 

Результатом этого является то, что Ctrl-C не надежно убивает все, и мой терминал всегда становится искаженным после (я должен запустить 'reset'). Итак, как я могу убить оба удаленных сценария, когда главный убит?

Примечание. Я пытаюсь избежать входа в удаленный хост, ища «script.sh» в списке процессов и отправляя SIGINT для обоих процессов. Я просто хочу, чтобы иметь возможность нажимать Ctrl-C на сценарий kickoff и убивать оба удаленных процесса. Менее оптимальное решение может включать детерминированное определение PID удаленных сценариев, но я не знаю, как это сделать в моей текущей настройке.

Обновление: скрипт, который запускается на удаленном сервере, фактически запускает несколько дочерних процессов, и, убивая ssh он убивает оригинальный удаленный сценарий (возможно, b / c SIGHUP), задачи для детей не убиваются.

5 Solutions collect form web for “Отправить Ctrl-C для удаленных процессов, запущенных через подпроцесс.Popen и ssh”

Единственный способ, которым я смог успешно убить все мои дочерние процессы, был с помощью pexpect :

 a = pexpect.spawn(['ssh', 'remote-host', './script.sh', 'a']) a.expect('something') b = pexpect.spawn(['ssh', 'remote-host', './script.sh', 'b']) b.expect('something else') # ... # to kill ALL of the children a.sendcontrol('c') a.close() b.sendcontrol('c') b.close() - a = pexpect.spawn(['ssh', 'remote-host', './script.sh', 'a']) a.expect('something') b = pexpect.spawn(['ssh', 'remote-host', './script.sh', 'b']) b.expect('something else') # ... # to kill ALL of the children a.sendcontrol('c') a.close() b.sendcontrol('c') b.close() 

Это достаточно надёжно. Я считаю, что кто-то еще опубликовал этот ответ раньше, но затем удалил ответ, поэтому я отправлю его на случай, если кому-то интереснее.

Когда он будет убит, ssh отправит SIGHUP в удаленные процессы. Вы можете обернуть удаленные процессы в сценарий оболочки или питона, который их убьет, когда этот скрипт получит SIGHUP (см. Команду trap для bash и сигнальный модуль в python)

Возможно, это возможно даже с раздутой командной строкой вместо сценария удаленной оболочки.

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

Я не пробовал это, но, возможно, вы можете поймать KeyboardInterrupt и затем убить процессы:

 try a = subprocess.Popen(['ssh', '-t', 'remote-host', './script.sh', 'a']) b = subprocess.Popen(['ssh', '-t', 'remote-host', './script.sh', 'b']) a.communicate() b.communicate() except KeyboardInterrupt: os.kill(a.pid, signal.SIGTERM) os.kill(b.pid, signal.SIGTERM) 

Я столкнулся с подобной проблемой этой проблемой, разобрав все сигналы, о которых я заботился. Когда Ctrl + C нажата, он все равно будет передан в подпроцесс, но Python будет ждать, пока подпроцесс не выйдет перед обработкой сигнала в главном скрипте. Это отлично работает для сигнального подпроцесса, пока подпроцесс отвечает на Ctrl + C.

 class DelayedSignalHandler(object): def __init__(self, managed_signals): self.managed_signals = managed_signals self.managed_signals_queue = list() self.old_handlers = dict() def _handle_signal(self, caught_signal, frame): self.managed_signals_queue.append((caught_signal, frame)) def __enter__(self): for managed_signal in self.managed_signals: old_handler = signal.signal(managed_signal, self._handle_signal) self.old_handlers[managed_signal] = old_handler def __exit__(self, *_): for managed_signal, old_handler in self.old_handlers.iteritems(): signal.signal(managed_signal, old_handler) for managed_signal, frame in self.managed_signals_queue: self.old_handlers[managed_signal](managed_signal, frame) 

Теперь мой код подпроцесса выглядит следующим образом:

  with DelayedSignalHandler((signal.SIGINT, signal.SIGTERM, signal.SIGHUP)): exit_value = subprocess.call(command_and_arguments) 

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

Существует оболочка paramiko, ssh_decorate которая имеет метод ctrl

 from ssh_decorate import ssh_connect ssh = ssh_connect('user','password','server') ssh.ctrl('c') 

Не может быть проще

  • Как определить, какой пользователь и группа запускает скрипт Python?
  • Что такое стандартные потоки, если нет окна терминала / консоли для интерпретатора python?
  • Отдельный текстовый файл в несколько файлов на основе определенного шаблона
  • Привет, мир Cron не работает
  • Изменение даты и времени на отметку времени Unix в Python
  • Демон Python не будет работать в фоновом режиме на Ubuntu
  • есть ли встроенный аналог python для unix wc для обнюхивания файла?
  • Как найти все установки python на mac os x и удалить все, кроме встроенной установки OS X
  • Python - лучший язык программирования в мире.