Python: форк, труба и exec - PullRequest
       85

Python: форк, труба и exec

3 голосов
/ 09 февраля 2012

Я хочу выполнить программу в приложении на Python, она будет работать в фоновом режиме, но в конечном итоге выйдет на передний план.

GUI используется для взаимодействия с ним.Но элементы управления предлагаются через консоль на stdin и stdout.Я хочу иметь возможность управлять им с помощью графического интерфейса моего приложения, поэтому моей первой идеей было:

  • Fork
  • в родительском объекте, dup2 stdin и stdout для доступа к ним
  • exec the child

Легко ли это реализовать на python и как?Существуют ли альтернативные способы достижения того, чего я хочу, что бы это было?

Ответы [ 3 ]

6 голосов
/ 09 февраля 2012

Это достаточно просто, используя стандартный модуль подпроцесса Python:

http://docs.python.org/py3k/library/subprocess.html

4 голосов
/ 09 февраля 2012

Это не так сложно по структуре, чтобы построить!

Проверьте этот пример

if os.fork():
    os._exit(0)
    os.setsid()
    os.chdir("/")
    fd = os.open("/dev/null", os.O_RDWR)
    os.dup2(fd, 0)
    os.dup2(fd, 1)
    os.dup2(fd, 2)
if fd 2:
    os.close(fd)

Этот код Python устанавливает идентификатор, изменяет каталог, открывает файл, обрабатывает и закрывает!

1 голос
/ 26 марта 2019

Во-первых, модуль подпроцесса python является правильным ответом.

В качестве примера подпроцесса:

import subprocess
x = subprocess.check_output(["echo","one","two","three"])

Где x будет выводиться (класс байтов python3: x.decode('utf-8') для строки)

Обратите внимание, что это не будет дублировать stderr. Если вам нужен также stderr, вы можете сделать что-то вроде:

x = subprocess.check_output(["bash","-c", 'echo foo; echo bar >&2'],stderr=subprocess.STDOUT)

Конечно, есть много других способов захвата stderr, в том числе в другую выходную переменную.

Использование прямого управления

Однако, если вы делаете что-то хитрое и нуждаетесь в прямом контроле, ответ @ Beginner имеет несколько недостатков: был включен os._exit (0), который немедленно приводит к выходу ребенка, делая все остальное бессмысленным. Нет os.execve (), делающего основную цель вопроса бессмысленной. Нет другого способа получить доступ к stdout / stderr ребенка как к другой цели вопроса.

import os
rside, wside = os.pipe()
if not os.fork():
    # Child

    os.close(rside)
    # Make stdout go to parent
    os.dup2(wside, 1)
    # Make stderr go to parent
    os.dup2(wside, 2)
    # Optionally make stdin come from nowhere
    devnull = os.open("/dev/null", os.O_RDONLY)
    os.dup2(devnull, 0)
    # Execute the desired program
    os.execve("/bin/bash",["/bin/bash","-c","echo stdout; echo stderr >&2"],os.environ)
    print("Failed to exec program!")
    sys.exit(1)

# Parent
os.close(wside)
pyrside = os.fdopen(rside)

for line in pyrside:
   print("Child (stdout or stderr) said: <%s>"%line)

# Prevent zombies!  Reap the child after exit
pid, status = os.waitpid(-1, 0)
print("Child exited: pid %d returned %d"%(pid,status))
...