如何可靠地确定句柄是否是 Haskell 中的终端?

How to reliably determine if a Handle is a terminal in Haskell?

我正在使用 System.IO.hIsTerminalDevice 来确定 Handle 是否为终端,如果是,则应用着色。我注意到当使用 CreatePipe 作为新进程 stdin 和 stdout 的流分叉一个进程时,这个函数 returns True 似乎是错误的答案:A pipe should not be considered as a终端。我试图通过查看 System.IOSystem.POSIX.IO 源代码来找出问题,但它最终出现在 C pipe 函数中,让我无处可去。

有没有更好的方法来判断句柄是否是终端?还是我做错了什么?

更新

这里有 2 个程序应该暴露我观察到的行为:

import           Control.Monad
import           System.IO
import           System.Process

main = do
  (in_, Just out, Just err, h) <-  createProcess $ (proc "./test2" [])
                                   { std_in = CreatePipe
                                   , std_err = CreatePipe
                                   , std_out = CreatePipe }
  dump out
  where
    dump h = forever $ do
      ln <- hGetLine h
      putStrLn ln

然后`test2:

import           System.IO

main = do
  print =<< hIsTerminalDevice stderr
  print =<< hIsTerminalDevice stdout
  print =<< hIsTerminalDevice stdin

然后运行第一个程序:

$ ./test
False
False
False

我知道发生了什么:我分叉的不是程序本身,而是一个 docker 容器!我明确地添加了 -t 参数,它为容器分配了一个 tty...

你有一个最小的例子来说明这个问题吗?以下程序打印 "False" 两次,表明使用 CreatePipe 创建的句柄 而不是 被错误识别为终端设备:

import System.Process
import System.IO

main = do (Just in_, Just out, err, h) <-
            createProcess $ (shell "cat") { std_in = CreatePipe,
                                            std_out = CreatePipe }
          print =<< hIsTerminalDevice in_
          print =<< hIsTerminalDevice out