【问题标题】:How can I cheat program that stdin is terminal (and not redirected file)?如何欺骗 stdin 是终端(而不是重定向文件)的程序?
【发布时间】:2015-09-21 05:23:36
【问题描述】:

我正在做标准重定向:

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

但如果我直接在终端中运行并复制粘贴输入,程序的行为会有所不同。 当输入是终端时,它会显示一个进度条。无论如何,我想要进度条。

简而言之,我如何“欺骗”程序输入来自终端而不是从文件重定向?

【问题讨论】:

  • /usr/bin/program file.txt 不起作用?
  • /usr/bin/program < file.txt?
  • 传统的做法是使用expect

标签: bash terminal stdin


【解决方案1】:

使用expect 程序可能是最简单的;它会为您完成大部分必要的工作。

必要的工作很繁琐。它涉及使用伪 tty,这些设备看起来像终端一样的程序。如果您要自己动手,那么您需要了解的 POSIX 系统调用是:

posix_openpt() 接口相对较新(第 6 版,与第 4 版相比,第 2 版列出的其他功能)。如果你的系统没有posix_openpt(),你需要给自己买一本 Unix 书籍(可能是 Stevens 或 Rochkind),以了解如何打开 pty 的 master 端,或者仔细阅读你的系统手册.但是,上面链接中posix_openpt() 的基本原理也可能有所帮助——它也有使用其他功能的指南。 Linux有posix_openpt(); Mac OS X 和 BSD 系统通常也是如此。

书籍:

【讨论】:

  • 如果应该产生彩色输出的程序位于shell管道的中间怎么办?我认为它是否被期望调用并不重要
  • @hek2mgl:如果程序在管道中间,默认情况下它可能不会产生颜色输出,但可能有一个选项可以强制它自动着色(可能拼写错误选项,例如--color=force)。
  • 你太快了 :) 我正要通过“最后”来纠正“中间”..(因为中间没有意义)
  • @hek2mgl: 很抱歉反应太快了 :D ... 在管道结束时,该命令通常会检测其输出是否为“终端”,如果是,它会考虑为输出着色。可能有一个选项可以强制它着色;当它做出“错误”决定时,可能无法影响它。
  • 然而,这里已经很晚了。感谢您的快速回复:)顺便说一句,很好的答案:)
【解决方案2】:

您需要使用伪 tty 才能获得您想要的效果。 '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;
    }
    

    生成文件

    # 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
    

    您应该会看到彩色输出。

    【讨论】:

      猜你喜欢
      • 2010-11-26
      • 2023-03-09
      • 2015-09-15
      • 2017-10-31
      • 2012-01-29
      • 1970-01-01
      相关资源
      最近更新 更多