Can you fool isatty AND log stdout and stderr separately?

前端 未结 4 1739
悲&欢浪女
悲&欢浪女 2020-12-28 12:55

Problem

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

相关标签:
4条回答
  • 2020-12-28 13:08

    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])
    
    0 讨论(0)
  • 2020-12-28 13:16

    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;
    }
    
    0 讨论(0)
  • 2020-12-28 13:20

    When you can use the script command:

    $ script --return -c "[executable string]" >stdout 2>stderr
    
    0 讨论(0)
  • 2020-12-28 13:21

    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.

    0 讨论(0)
提交回复
热议问题