So you want to log the stdout and stderr (separately) of a process or subprocess, without the output being different from what you\'d see in the terminal i
You can always allocate Pseudo-TTY, that's what screen
does.
In Python you'd access it using pty.openpty()
This "master" code passes your test:
import subprocess, pty, os
m, s = pty.openpty()
fm = os.fdopen(m, "rw")
p = subprocess.Popen(["python2", "test.py"], stdin=s, stdout=s, stderr=s)
p.communicate()
os.close(s)
print fm.read()
Of course if you want to distinguish between stdin/out/err, your "slave" process will see different PYT names:
inp = pty.openpty()
oup = pty.openpty()
erp = pty.openpty()
subprocess.Popen([command, args], stdin=inp[1], stdout=uop[1], stderr=erp[1])
Like this?
% ./challenge.py >stdout 2>stderr
% cat stdout
This is a real tty :)
standard output data
% cat stderr
standard error data
Because I cheated a little bit. ;-)
% echo $LD_PRELOAD
/home/karol/preload.so
Like so...
% gcc preload.c -shared -o preload.so -fPIC
I feel dirty now, but it was fun. :D
% cat preload.c
#include <stdlib.h>
int isatty(int fd) {
if(fd == 2 || fd == 1) {
return 1;
}
return 0;
}
char* ttyname(int fd) {
static char* fake_name = "/dev/fake";
if(fd == 2 || fd == 1) {
return fake_name;
}
return NULL;
}
When you can use the script command:
$ script --return -c "[executable string]" >stdout 2>stderr
For a simpler use-case (e.g. development testing), use strace
(linux) or dtruss
(OSX). Of course that won't work in privileged process.
Here's a sample, you can distinguish stdout
fd1 from stderr
fd2:
$ strace -ewrite python2 test.py
[snip]
write(1, "This is a real tty :)\n", 22This is a real tty :)
) = 22
write(2, "standard error data", 19standard error data) = 19
write(1, "standard output data", 20standard output data) = 20
+++ exited with 0 +++
In the sample above you see each standard xxx data
doubled, because you can't redirect stdout/stderr. You can, however ask strace
to save its output to a file.
On a theoretical side, if stdout
and stderr
refer to the same terminal, you can only distinguish between the 2 while still in the context of your process, either in user mode (LD_PRELOAD), or kernel space (ptrace interface that strace tool uses). Once the data hits actual device, real of pseudo, the distinction is lost.