Ctrl C не уничтожит зацикленный подпроцесс в Python

#python #subprocess #system-calls #kill

#python #подпроцесс #системные вызовы #убить

Вопрос:

Есть ли правильный способ создать скрипт, который перебирает файлы в папке и выполняет подпроцесс, который может быть отключен извне с помощью Ctrl C? У меня есть что-то вроде следующего, встроенного в конвейер, и я не могу нажать Ctrl C из командной строки, когда основной процесс остановлен.

Пример скрипта:

 import subprocess
import os
import sys

input_directory = sys.argv[1]

for file in os.listdir(os.path.abspath(input_directory)):
    output = file   "_out.out"
    command = ['somescript.py', file, output]
    try:
        subprocess.check_call(command)
    except:
        print "Command Failed"
  

Затем я бы выполнил program:

 Example_script.py /path/to/some/directory/containing/files/
  

Во время выполнения цикла, если я вижу, что команда выполнена с ошибкой, я хочу использовать Ctrl C. Однако он завершается с ошибкой и продолжает запускать дополнительные подпроцессы, несмотря на то, что основной скрипт был уничтожен с помощью Ctrl C. Есть ли правильный способ написать что-то подобное, что может уничтожить дочерние элементы (дополнительный подпроцесс) с помощью Ctrl C?

Любая помощь или указание мне направления очень ценятся. В настоящее время я ищу хороший метод для выполнения.

Комментарии:

1. Почему бы просто не выйти из вашей программы, когда вы перехватываете исключение, после печати «Сбой команды»? — Вы можете усложнить этот процесс, добавив в свой код обработку сигналов, которая вызывается при смерти дочернего процесса, но в этом случае кажется, что вы просто хотите прекратить цикл при сбое. … или вы хотите сказать, что в этом случае вы не получаете исключения?

2. @Steve Я не знаю, почему я еще этого не пробовал. лол, это буквально меня еще не поразило. Спасибо! Если бы я хотел попробовать более сложную обработку сигналов, как бы я это сделал? Буду ли я проверять состояние подпроцесса, когда он вернется?

Ответ №1:

То, что у вас есть в вашем блоке try / except, слишком разрешительно, так что при нажатии Ctrl C KeyboardInterrupt исключение также обрабатывается тем же обработчиком исключений, что и тот, который print "Command Failed" , и поскольку это теперь обрабатывается там должным образом, поток программы продолжается через цикл for. Что вам следует сделать, так это:

  1. Замените except: на except Exception: , чтобы KeyboardInterrupt исключение не было захвачено, так что при любом нажатии Ctrl C программа завершится (включая подпроцессы, которые не застряли в каком-либо не завершаемом состоянии);
  2. После print инструкции break завершите цикл, чтобы предотвратить дальнейшее выполнение, если вы хотите, чтобы эта программа выполняла именно такое поведение.

Комментарии:

1. Спасибо за ваш ответ. Я тоже попробую это сделать. 🙂 Я обязательно отвечу с обновлениями.

Ответ №2:

Вы можете перехватывать KeyboardInterrupt , таким образом, вы можете обрабатывать Ctrl C любым способом, который вы хотите.

 import subprocess
import os
import sys

input_directory = sys.argv[1]

for file in os.listdir(os.path.abspath(input_directory)):
    output = file   "_out.out"
    command = ['somescript.py', file, output]
    try:
        subprocess.check_call(command)
    except KeyboardInterrupt as e:
        print "Interrupted"
        sys.exit(1)
    except:
        print "Command Failed"
  

Однако я согласен с другими постерами в том, что ваше исключение слишком расплывчатое, и вам следует быть более конкретным в том, что может и не может завершиться ошибкой.

Ответ №3:

Я думаю, Ctrl Z также может помочь вам перевести выполнение в фоновый режим и приостановить его.