Python: выполнение долго выполняющегося процесса с помощью subprocess.Popen, его уничтожение и доступ к его выводу - PullRequest
0 голосов
/ 29 ноября 2018

Я пытаюсь запустить «длительный» процесс от имени пользователя root (потому что мне нужно), в потоке, на python, затем уничтожить его и затем получить доступ к его выводу.

рассматриваемый процесс - "babeld", и когда я просто запускаю его в терминале, он выводит текст на стандартный вывод.Тем не менее, когда я запускаю следующий код, у меня нет доступа к stderr или stdout:

% ./example.py                                                                                                                                                                                                                                                                                   
Waiting for output
Pgid: 13445, pid: 13445
Stopping task
Permission Error!
Calling sudo kill 13445
B
None
None
End

Код:

#!/usr/bin/env python3

import subprocess
import threading
import time
import os

def main():
    task = TaskManager()
    task.launch()
    time.sleep(2)
    task.stop()

    print(task.stdout)
    print(task.stderr)


class TaskManager(threading.Thread):
    def __init__(self):
        super().__init__()
        self.start_event = threading.Event()
        self.stderr = None
        self.stdout = None
        self.pgid = None
        self.task = None
        self.start()


    def run(self):
        self.start_event.wait()
        self.task = subprocess.Popen(["sudo", "babeld", "-d", "2", "wlp2s0"],
                                     stdout=subprocess.PIPE,
                                     stderr=subprocess.PIPE,
                                     preexec_fn=os.setsid)
        self.pgid = os.getpgid(self.task.pid)
        print("Waiting for output")
        self.stdout, self.stderr = self.task.communicate()
        print("End")

    def launch(self):
        self.start_event.set()

    def stop(self):
        print("Pgid: %s, pid: %s" % (self.pgid, self.task.pid))
        try:
            print("Stopping task")
            self.task.terminate()
        except PermissionError:
            print("Permission Error!")
            print("Calling sudo kill %d" % self.pgid)
            subprocess.check_call(["sudo", "kill", str(self.pgid)])
            print("B")

if __name__ == '__main__':
    main()

Как правильно завершить процессы, работающие от имени пользователя root,имея доступ к своим stderr и stdout?

Спасибо,

1 Ответ

0 голосов
/ 29 ноября 2018

Рецепт прост: не используйте communicate.Вы можете заменить атрибуты класса self.stdout и self.stderr следующими получателями:

@property
def stdout(self):
    return self.task.stdout.read()

@property
def stderr(self):
    return self.task.stderr.read()

Кстати, этот подход дает вам возможность отказаться от использования потоков в вашем коде.Пример:

# !/usr/bin/env python3

import subprocess
import time
import os


def main():
    task = TaskManager()
    task.launch()
    time.sleep(2)
    task.stop()

    print(task.stdout)
    print(task.stderr)


class TaskManager:
    def __init__(self):
        self.pgid = None
        self.task = None

    @property
    def stdout(self):
        return self.task.stdout.read()

    @property
    def stderr(self):
        return self.task.stderr.read()

    def launch(self):
        self.task = subprocess.Popen(["sudo", "babeld", "-d", "2", "wlp2s0"],
                                     stdout=subprocess.PIPE,
                                     stderr=subprocess.PIPE,
                                     preexec_fn=os.setsid)
        self.pgid = os.getpgid(self.task.pid)
        print("Waiting for output")

    def stop(self):
        print("Pgid: %s, pid: %s" % (self.pgid, self.task.pid))
        try:
            print("Stopping task")
            self.task.terminate()
        except PermissionError:
            print("Permission Error!")
            print("Calling sudo kill %d" % self.pgid)
            subprocess.check_call(["sudo", "kill", str(self.pgid)])
            print("B")


if __name__ == '__main__':
    main()
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...