Question

How can I execute a shell command, can be complicated like normal command in bash command line, get the output of that command and pwd after execution?

I used function like this:

import subprocess as sub

def execv(command, path):
    p = sub.Popen(['/bin/bash', '-c', command],
                    stdout=sub.PIPE, stderr=sub.STDOUT, cwd=path)
    return p.stdout.read()[:-1]

And I check if user use cd command but that will not work when user use symlink to cd or other wierd way to change directory.

and I need a dictionary that hold {'cwd': '<NEW PATH>', 'result': '<COMMAND OUTPUT>'}

Was it helpful?

Solution 3

I redirect stdout to stderr of pwd command. if stdout is empty and stderr is not a path then stderr is error of the command

import subprocess as sub

def execv(command, path):
    command = 'cd %s && %s && pwd 1>&2' % (path, command)
    proc = sub.Popen(['/bin/bash', '-c', command],
                     stdout=sub.PIPE, stderr=sub.PIPE)
    stderr = proc.stderr.read()[:-1]
    stdout = proc.stdout.read()[:-1]
    if stdout == '' and not os.path.exists(stderr):
        raise Exception(stderr)
    return {
        "cwd": stderr,
        "stdout": stdout
    }

UPDATE: here is better implemention (using last line for pwd and don't use stderr)

def execv(command, path):
    command = 'cd %s && %s 2>&1;pwd' % (path, command)
    proc = sub.Popen(['/bin/bash', '-c', command],
                     env={'TERM':'linux'},
                     stdout=sub.PIPE)
    stdout = proc.stdout.read()
    if len(stdout) > 1 and stdout[-1] == '\n':
        stdout = stdout[:-1]
    lines = stdout.split('\n')
    cwd = lines[-1]
    stdout = '\n'.join(lines[:-1])
    return {
        "cwd": cwd,
        "stdout": man_to_ansi(stdout)
    }

OTHER TIPS

If you use subprocess.Popen, you should get a pipe object that you can communicate() for the command output and use .pid() to get the process id. I'd be really surprised if you can't find a method to get the current working directory of a process by pid...

e.g.: http://www.cyberciti.biz/tips/linux-report-current-working-directory-of-process.html

To get output of an arbitrary shell command with its final cwd (assuming there is no newline in the cwd):

from subprocess import check_output

def command_output_and_cwd(command, path):
    lines = check_output(command + "; pwd", shell=True, cwd=path).splitlines()
    return dict(cwd=lines[-1], stdout=b"\n".join(lines[:-1]))
Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top