heretoinfinity
heretoinfinity

Reputation: 1746

Interpret output from bash in Python's subprocess module

I have been going through the subprocess module examples on Doug Helmann's PYMOPTW. Here's the code snippet that I have trouble with.

# subprocess_run_output_error.py
import subprocess

try:
    completed = subprocess.run(
        'echo to stdout; echo to stderr 1>&2; exit 1',
        check=True,
        shell=True,
        stdout=subprocess.PIPE,
    )
except subprocess.CalledProcessError as err:
    print('ERROR:', err)
else:
    print('returncode:', completed.returncode)
    print('Have {} bytes in stdout: {!r}'.format(
        len(completed.stdout),
        completed.stdout.decode('utf-8'))
    )

I understand that exit 1 is supposed to throw an error and the except clause is run.

to stderr 
ERROR: Command 'echo to stdout; echo to stderr 1>&2; exit 1' returned non-zero exit status 1.

I don't get why to stdout is not printed but to stderr. Doesn't 1>&2 appear after echo to stdout has been run?

For better understanding, I changed the code to see if I could get the else portion to run so I switched it to exit 0. When I did so, the output that I got was:

to stderr
returncode: 0
Have 10 bytes in stdout: 'to stdout\n'

I don't seem to understand what the 1>2 means despite going to cheatsheets.

  1. Again to stderr was printed. Why isn't to stdout printed out first since it appeared first?

  2. Why is the CompletedProcess object only holding on to to stderr and not to stdout?

  3. If I understand the cheatsheet's portion below, why isn't to stderr sent to the standard error stream if it's file descriptor is 2?

n>&m # file descriptor n is made to be a copy of the output file descriptor

The other question that I found relatively close to this was this. However, it was comparing &> and >&. I couldn't make sense of the initial >& so I felt even more confused.

Upvotes: 0

Views: 163

Answers (1)

Poshi
Poshi

Reputation: 5762

  1. Because you captured it, sou you have it available at completed.stdout.
  2. Because you only captured stdout: stdout=subprocess.PIPE, but no stderr=subprocess.PIPE
  3. It is actually sent to stderr, that's why it is printed at the beginning, because you didn't captured it and that stream is unbuffered.

Upvotes: 1

Related Questions