Search code examples
pythonbashshellsubprocesspwd

How to execute shell command get the output and pwd after the command in Python


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>'}


Solution

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