如何欺骗程序,让stdin看起来像终端而不是重定向文件?

3

我正在进行标准重定向:

$ cat file.txt | /usr/bin/program

但是,如果我直接在终端中运行程序并复制粘贴输入时,程序的行为会有所不同。

当输入来自终端时,程序会显示进度条。无论如何,我都想要这个进度条。

简而言之,我该如何“欺骗”程序,让它认为输入来自终端并且不是从文件重定向过来的?


/usr/bin/program file.txt不能工作? - Explosion Pills
还是 /usr/bin/program < file.txt - squiguy
1
传统的方法是使用 expect - Adrian Pronk
3个回答

5
可能最简单的方法是使用 expect 程序;它会为您完成大部分必要的工作。
必要的工作有些棘手。它涉及使用伪终端,这是一种对程序来说像终端的设备。如果您打算自己编写代码,则需要了解以下 POSIX 系统调用: posix_openpt() 接口相对较新(与其他列出的函数相比,Issue 6 而不是 Issue 4,Version 2)。如果您的系统没有 posix_openpt(),则需要获取一本 Unix 书籍(可能是 Stevens 或 Rochkind)以查找如何打开 pty 的主端,或者仔细阅读系统手册。但是,上面链接的 posix_openpt() 的原理也可能有所帮助,它还提供了使用其他函数的指南。Linux 有 posix_openpt();Mac OS X 以及 BSD 系统通常也有。
书籍:

如果应该产生彩色输出的程序在shell管道的中间,会发生什么情况?我假设它是否被expect调用都无关紧要。 - hek2mgl
如果程序位于管道中间,则默认情况下它可能不会生成彩色输出,但可能有一种选项可以强制自动进行着色(可能是一个拼写错误的选项,例如 --color=force)。 - Jonathan Leffler
你太快了 :) 我正要把“在中间”改为“在结尾”……(因为在这里“在中间”没有意义) - hek2mgl
@hek2mgl:抱歉我回复太快了:D...在管道的末尾,通常命令会检测它的输出是否是“终端”,如果是,它将考虑对输出进行着色。可能有一种选项可以强制着色,当它做出“错误”的决定时,可能没有影响它的方法。 - Jonathan Leffler
不过,这里已经很晚了。感谢您的快速回复 :) 顺便说一下,答案很好 :) - hek2mgl

3

您需要使用伪终端才能达到您想要的效果。'man pty' 将为您提供更多信息。


3
我假设该程序将调用glibc函数isatty()来检查stdin/stdout是否为终端。这对于那些在终端上使用彩色输出或其他ANSI终端功能(如光标定位或行擦除/重绘)的程序很常见。
您可以通过LD_PRELOAD环境变量欺骗程序。LD_PRELOAD由ELF链接器处理,并告诉应加载动态库在所有其他库之前。使用此功能,可以覆盖库函数,在您的情况下是glibc函数isatty()
这里有一个例子: libisatty.c
/**
 * Overrides the glibc function. Will always return true.
 *
 * Note: Although this should be ok for most applications it can
 * lead to unwanted side effects. It depends on the question
 * why the programm calls isatty()
 */
int isatty(int param) {
    return 1;
}

Makefile

# Make the shared Library
lib: libisatty.c
    gcc -shared -Wl,-soname,libisatty.so.1 -o libisatty.so.1.0  libisatty.c 
    ln -s libisatty.so.1.0 libisatty.so.1
    ln -s libisatty.so.1 libisatty.so

运行:

make lib

它应该能够正常构建,我已在Ubuntu12.04 AMD 64上进行了测试。

现在是测试库的时候了。 :) 我使用了ls --color=auto命令进行测试。ls调用isatty()来决定是否应该对其输出着色。如果输出被重定向到文件或管道中,则不会着色。您可以轻松使用以下命令进行测试:

ls --color=auto        # should give you colorized output
ls --color=auto | cat  # will give you monochrome output

现在我们将再次尝试使用LD_PRELOAD环境变量执行第二个命令:
LD_PRELOAD=libisatty.so ls --color=auto | cat

您应该看到有色彩的输出。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接