0

I have a program which can be execute as

./install.sh

This install bunch of stuff and has quite a lot of activity happening on screen..

Now, I am trying to execute it via

p = subprocess.Popen(executable, stdout=subprocess.PIPE, stderr=subprocess.PIPE)
out, err = p.communicate()

With the hope that all the activity happening on the screen is captured in out (or err). However, content is printed directly to the terminal while the process is running, and not captured into out or err, which are both empty after the process is run.

What could be happening here? How can this content be captured?

9
  • Why do you think you were wrong? (It's possible for a program to bypass this kind of capture by using /dev/tty instead of stdout and stderr, but few do). Commented Jan 13, 2015 at 23:46
  • The above output should work. Another mechanism would be to use subprocess.check_output Commented Jan 13, 2015 at 23:47
  • What you have looks (to me) like it should work... I suppose without knowing more about the executable and how you're running it, it's really hard to give any advice here... Commented Jan 13, 2015 at 23:47
  • You could call os.setsid() to detach from your controlling terminal if you think the process is connecting to /dev/tty directly. Commented Jan 13, 2015 at 23:49
  • @Fraz, are you also checking the output of print err? Also, are you sure that your program emits any output at all when it detects that stdout isn't connected directly to a terminal? (It's not uncommon for software to detect this case and behave differently). Commented Jan 13, 2015 at 23:51

1 Answer 1

7

In general, what you're doing is already sufficient to channel all output to your variables.

One exception to that is if the program you're running is using /dev/tty to connect directly to its controlling terminal, and emitting output through that terminal rather than through stdout (FD 1) and stderr (FD 2). This is commonly done for security-sensitive IO such as password prompts, but rarely seen otherwise.


As a demonstration that this works, you can copy-and-paste the following into a Python shell exactly as given:

import subprocess
executable = ['/bin/sh', '-c', 'echo stdout; echo stderr >&2']
p = subprocess.Popen(executable, stdout=subprocess.PIPE, stderr=subprocess.PIPE)
out, err = p.communicate()
print "---"
print "output: ", out
print "stderr: ", err

...by contrast, for a demonstration of the case that doesn't work:

import subprocess
executable = ['/bin/sh', '-c', 'echo uncapturable >/dev/tty']
p = subprocess.Popen(executable, stdout=subprocess.PIPE, stderr=subprocess.PIPE)
out, err = p.communicate()
print "---"
print "output: ", out

In this case, content is written to the TTY directly, not to stdout or stderr. This content cannot be captured without using a program (such as script or expect) that provides a fake TTY. So, to use script:

import subprocess
executable = ['script', '-q', '/dev/null',
              '/bin/sh', '-c', 'echo uncapturable >/dev/tty']
p = subprocess.Popen(executable, stdout=subprocess.PIPE, stderr=subprocess.PIPE)
out, err = p.communicate()
print "---"
print "output: ", out
Sign up to request clarification or add additional context in comments.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.