pythonsubprocesspopen

How can I get the command output instead of the subprocess in python?


If I do like:

x = subprocess.Popen(["nosetests",      
"TestStateMachine.py:FluidityTest.test_it_has_an_initial_state", "-v"], 
stdout=subprocess.PIPE)

I have the output from my command executed:

test_it_has_an_initial_state (TestStateMachine.FluidityTest) ... ok

----------------------------------------------------------------------
Ran 1 test in 0.001s

OK

But if call x.communicate() for example I got:

('', None)

How can I save that message in a variable, for example?


Solution

  • The problem is almost certainly that your command is writing to stderr as well as to stdout, and you're only capturing stdout.

    If you want to merge the two together into one string, do this:

    x = subprocess.Popen(["nosetests",
                          "TestStateMachine.py:FluidityTest.test_it_has_an_initial_state", 
                          "-v"], 
                         stdout=subprocess.PIPE, stderr=subprocess.STDOUT)
    
    out_and_err, _ = x.communicate()
    

    If you want to get them as separate strings:

    x = subprocess.Popen(["nosetests",
                          "TestStateMachine.py:FluidityTest.test_it_has_an_initial_state", 
                          "-v"], 
                         stdout=subprocess.PIPE, stderr=subprocess.PIPE)
    
    out, err = x.communicate()
    

    This is explained under Frequently Used Arguments:

    stdin, stdout and stderr specify the executed program’s standard input, standard output and standard error file handles, respectively. Valid values are… Additionally, stderr can be STDOUT, which indicates that the stderr data from the child process should be captured into the same file handle as for stdout.

    However, if you'd never heard of standard error before, it's understandable that you wouldn't have gone looking for this… The docs assume you know the basic C/POSIX model of separate output and error pipes for every program.


    As a side note, if all you want to run is run a program and get its output, merging its stderr in with its stdout, you don't need to create a Popen and call communicate on it; just use check_output:

    out_and_err = subprocess.check_output([… args …], stderr=subprocess.STDOUT)