isatty() 如何从终端获取信息?

isatty() 如何从终端获取信息?

我注意到如果我输入:

ls --color=auto

或者

ls --color=auto | cat
ls --color=auto > >(cat)

我没有看到相同的输出。因此我假设程序有能力知道其 STDOUT 是否通过管道传输到某个东西。问题是它如何知道?

env我使用和检查了 ENV 变量env | cat,但得到的结果相同。答案在其他地方。我搞不清楚在哪里。

由此问题我发现我可以使用isatty()谁提供这个函数?它是 shell 还是内核的一部分?通过进一步研究,我发现这个函数是 POSIX 标准的一部分。

现在我知道我有两个进程可以通过几种机制在它们之间进行通信:

  • 标准输入/标准输出/标准错误
  • 退出代码
  • 环境变量
  • 系统调用

Bash 和 ls 都是程序。因此,它们只能使用列出的机制来交换信息。

这背后真正的问题是如何isatty()从 bash 获取信息?

答案1

--color选项是 GNUls程序的一个功能。GNUls使用isatty()函数测试进程的标准输出是否是TTY。部分相关源代码可见这里

    case COLOR_OPTION:
      {
        int i;
        if (optarg)
          i = XARGMATCH ("--color", optarg, color_args, color_types);
        else
          /* Using --color with no argument is equivalent to using
             --color=always.  */
          i = color_always;

        print_with_color = (i == color_always
                            || (i == color_if_tty
                                && isatty (STDOUT_FILENO)));

这背后真正的问题是 isatty() 如何从 bash 获取信息?

isatty()检查传递给它的文件描述符,以查看文件描述符是否代表 TTY(终端设备)。isatty() 的具体工作方式可能因系统而异。下面是达尔文实现如果你有兴趣的话,可以参阅 Apple OSX:

#include <termios.h>
#include <unistd.h>

int
isatty(fd)
    int fd;
{
    struct termios t;

    return(tcgetattr(fd, &t) != -1);
}

当您运行 时ls --color=auto,您的 shell (bash) 将使用 shell 自己的标准输入、输出和错误作为“ls”进程的 stdin/out/err 来启动“ls”程序。如果您以交互方式运行,则 shell 的标准输出可能是一个终端,而 ls 的标准输出可能也是一个终端。当 ls 调用 isatty() 来测试其标准输出是否为终端时,它可能会成功。

当你运行类似的程序时ls --color=auto | cat,你的 shell 会做三件事:

  1. 创建管道。
  2. cat将其标准输入设置为管道来启动。
  3. ls将其标准输出设置为管道来启动。

管道不是终端,当ls测试它的标准输出是否是tty时,测试会失败。

相关内容