Grav
Grav

Reputation: 491

How to use pipes and redirects using os.execv(), if possible?

I'm getting a command and arguments from the user, parsing them, and passing them to os.execvp(), like so:

> ps -a -u -x

cmd = "ps"
args = ["-a", "-u", "-x"]
os.execvp(cmd, args)

The problem is that this doesn't work with pipes or redirects, so something like this wouldn't work:

> ps -a -u -x > output.txt

cmd = ps
args = ["-a", "-u", "-x", ">", "output.txt"]
os.execvp(cmd, args)

I understand that my problem is that > and output.txt are not arguments of ps, I just don't know the best way to solve this problem. I'm hoping I'm just missing the right method.

Upvotes: 5

Views: 2442

Answers (1)

VPfB
VPfB

Reputation: 17352

With os.execv we are at the low level of the OS.

To redirect the output, we need to replace the file descriptor no. 1 (stdout) before executing the command.

import os

STDOUT = 1

fdout = os.open('output.txt', os.O_WRONLY)
os.dup2(fdout, STDOUT)
os.execvp('ps', 'ps -a -u -x'.split())
# not reached
os._exit(127) # just for the case of execv failure

More work is required to connect two processes with a pipe. The pipe has two ends and must be created first. Then fork will duplicate the process. Each process must close one end of the pipe and redirect the other end to its stdin or stdout respectively.

import os

STDIN = 0 
STDOUT = 1 

pipein, pipeout = os.pipe()
if os.fork():
    # parent
    os.close(pipeout)
    os.dup2(pipein, STDIN)
    os.execlp('wc', '-l')
    # not reached
    os._exit(127)
else:
    # child
    os.close(pipein)
    os.dup2(pipeout, STDOUT)
    os.execvp('ps', 'ps -a -u -x'.split())
    # not reached
    os._exit(127)

These are just examples of concepts.

Upvotes: 5

Related Questions