关于bash:欺骗应用程序认为其stdout是终端,而不是管道

Trick an application into thinking its stdout is a terminal, not a pipe

我试着做与

检测stdin是终端还是管道?

我运行的应用程序正在更改其输出格式,因为它在stdout上检测到一个管道,我希望它认为它是一个交互式终端,以便在重定向时获得相同的输出。

我在想用expect脚本包装它,或者在PHP中使用proc_open()可以做到,但事实并非如此。

有什么想法吗?


啊哈!

script命令执行我们想要的…

1
script --return -c"[executable string]" /dev/null

耍把戏!


基于Chris的解决方案,我提出了以下小助手功能:

1
2
3
faketty() {
    script -qfc"$(printf"%q""$@")" /dev/null
}

为了在$@中正确地扩展脚本的参数,同时保护命令中可能引用的部分(见下面的示例),需要使用外观怪异的printf

用途:

1
faketty <command>

例子:

1
2
3
4
5
6
$ python -c"import sys; print sys.stdout.isatty()"
True
$ python -c"import sys; print sys.stdout.isatty()" | cat
False
$ faketty python -c"import sys; print sys.stdout.isatty()" | cat
True


Expect附带的unbuffer脚本应该处理这个OK。如果不是这样,应用程序可能正在寻找与其输出连接的对象以外的其他对象,例如,将术语环境变量设置为什么。


我不知道它是否可以从PHP实现,但是如果您真的需要子进程来查看tty,您可以创建一个pty。

在C:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
#include <stdio.h>
#include <stdlib.h>
#include <sysexits.h>
#include <unistd.h>
#include <pty.h>

int main(int argc, char **argv) {
    int master;
    struct winsize win = {
        .ws_col = 80, .ws_row = 24,
        .ws_xpixel = 480, .ws_ypixel = 192,
    };
    pid_t child;

    if (argc < 2) {
        printf("Usage: %s cmd [args...]
"
, argv[0]);
        exit(EX_USAGE);
    }

    child = forkpty(&master, NULL, NULL, &win);
    if (child == -1) {
        perror("forkpty failed");
        exit(EX_OSERR);
    }
    if (child == 0) {
        execvp(argv[1], argv + 1);
        perror("exec failed");
        exit(EX_OSERR);
    }

    /* now the child is attached to a real pseudo-TTY instead of a pipe,
     * while the parent can use"master" much like a normal pipe */
}

不过,我当时的印象是,expect本身确实创造了一个节目类型。


参考前面的答案,在Mac OS X上,"脚本"可以如下使用…

1
script -q /dev/null commands...

但是,因为它可能会将返回代码从""更改为"
",所以我需要这样运行。

1
2
3
4
script -q /dev/null commands... | perl -pe 's/

/
/g'

如果这些命令之间有一些管道,则需要清除stdout。例如:

1
2
3
4
5
script -q /dev/null commands... | ruby -ne 'print"....
";STDOUT.flush'
|  perl -pe 's/

/
/g'


对于具体的答案,我还不太了解,但我想我会跟进上面的Ingomueller网络发布的faketty函数,因为它最近帮助了我。

我发现这是在创建一个我不想要/不需要的typescript文件,所以我添加了/dev/null作为脚本目标文件:

function faketty { script -qfc"$(printf"%q""$@")" /dev/null ; }


在"Unix环境中的高级编程,第二版"这本书的示例代码中还包含一个pty程序!

以下是如何在Mac OS X上编译PTY:

http://codesnippets.joyent.com/posts/show/8786