Python: fork, pipe and exec
Asked Answered
M

3

8

I want to execute a program in a python application, it will run in the background but eventually come to the foreground.

A GUI is used to interact with it. But controls are offered via a console on stdin and stdout. I want to be able to control it using my application's GUI, so my first idea was:

  • Fork
  • in the parent, dup2 stdin and stdout in order to access them
  • exec the child

Is this easily implementable in python and how? Are there alternative ways to achieve what I want, what would that be?

Mae answered 9/2, 2012 at 12:54 Comment(1)
The answers are "yes" and "yes". Those answers to the questions you wrote don't seem helpful. Please update your question to clarify what you want to know.Bolt
C
5

This is reasonably easy using the standard Python subprocess module:

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

Cari answered 9/2, 2012 at 13:3 Comment(2)
Indeed, I'll go this way then. I was looking for 2.X modules, fortunately it has existed for a long time (docs.python.org/library/subprocess.html).Mae
The accepted answer should be https://mcmap.net/q/1278176/-python-fork-pipe-and-exec -- a mere link to the Python docs does not add sufficient value.Coachwhip
F
7

First, the python subprocess module is the correct answer.

As an subprocess example:

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

Where x will be the output (python3 bytes class: x.decode('utf-8') for string)

Note that this will NOT duplicate stderr. If you need stderr as well, you can do something like:

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

Of course, there are many other ways of capturing stderr, including to a different output variable.

Using direct control

However, if you are doing something tricky and need to have direct control, examine the code below:

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

Note: @Beginner's answer is flawed in a few ways: os._exit(0) was included which immediately causes the child to exit, rendering everything else pointless. No os.execve() rendering the primary goal of the question pointless. No way to access the child's stdout/stderr as another question goal.

Flounder answered 25/3, 2019 at 21:48 Comment(0)
C
5

This is reasonably easy using the standard Python subprocess module:

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

Cari answered 9/2, 2012 at 13:3 Comment(2)
Indeed, I'll go this way then. I was looking for 2.X modules, fortunately it has existed for a long time (docs.python.org/library/subprocess.html).Mae
The accepted answer should be https://mcmap.net/q/1278176/-python-fork-pipe-and-exec -- a mere link to the Python docs does not add sufficient value.Coachwhip
H
3

That is not much complex in structure to build !

Check this example

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)

This python code sets an id, changes the dir, opens a file and process and close !

Hodgkinson answered 9/2, 2012 at 12:59 Comment(1)
that's possibly how I would do it in C, but I hope python has some module that can help me achieve this simply and in a portable way.Mae

© 2022 - 2024 — McMap. All rights reserved.