检测 NUL 文件描述符(isatty 是假的)

Posted

技术标签:

【中文标题】检测 NUL 文件描述符(isatty 是假的)【英文标题】:Detect NUL file descriptor (isatty is bogus) 【发布时间】:2011-04-08 14:27:14 【问题描述】:

以下 C 文件在通过管道传递 NUL 时会给出虚假结果:

int main()

  printf("_isatty = %d\n", _isatty(0));

结果是:

C:\Users\Edward\Dev\nulltest> test.exe < NUL
_isatty = 64

我很确定 NUL(又名 /dev/null)不是终端设备!所以我需要以另一种方式检测文件描述符是否对应于NUL。该数字没有任何特定含义;当我确实连接了终端时,我会看到它。

我该怎么办? This question 建议使用粗略的未记录函数来获取底层名称,大概将其与 NUL 进行比较,但这对我来说感觉不太理想。有没有更好的办法?

附:这将有助于解决this GHC bug。

【问题讨论】:

只是出于兴趣(我并不是说您所做的事情是错误的):您为什么关心输入的来源? 有许多应用程序在检测到终端时会执行不同的操作。例如,如果你输入'python',它会进入交互模式,但是'echo "print \"bar\"" | python' 不会显示任何初始化屏幕。 好吧,在这种情况下,我只是在调试它,因为它会导致测试套件失败,我讨厌失败的测试套件 :-) 【参考方案1】:

来自msdn:

_isatty 如果描述符与 字符设备。否则,_isatty 返回 0。

NUL 就像 Unix 上的 /dev/null,它是一个字符设备。

注意,在 Linux 上,isatty 是不同的:

isatty() 函数测试 fd 是否 是一个打开的文件描述符,引用 到终端。

您可以尝试将 STDIN_FILENO (0) 与 $cwd/NUL 进行比较(使用 stat 或 stat)。

更新:

int ret = GetFileType(GetStdHandle(STD_INPUT_HANDLE));

它将为 NUL 或 tty 返回 FILE_TYPE_CHAR。

有关其他值,请参阅 GetFileType 文档。您可以检测文件/字符设备/管道。

最终更新:

使用GetConsoleMode 输入,GetConsoleScreenBufferInfo 输出。

CONSOLE_SCREEN_BUFFER_INFO sbi;
DWORD mode;
if (!GetConsoleMode(GetStdHandle(STD_INPUT_HANDLE), &mode))
   fprintf(stderr, "not console\n");
else
   fprintf(stderr, "console\n");
if (!GetConsoleScreenBufferInfo(GetStdHandle(STD_OUTPUT_HANDLE), &sbi))
   fprintf(stderr, "not console\n");
else
  fprintf(stderr, "console\n");

【讨论】:

有趣!这意味着我们实际上不应该使用 isatty 来检测是否有终端。 Windows 上是否有等效功能? _isatty 有问题,它应该检测您是否使用终端,而不是 fd 是否是字符设备。我不确定在 Windows 上最好的方法是什么。您可以尝试检查 cygwin/mingway isatty 的实现。您还可以创建一个将 $(CWD)/NUL 列入黑名单的包装器,因为它可能是您可以在 Windows 上轻松使用的唯一字符设备。 但是......这不区分 NUL 或 tty。 (我有点困惑。) 嗯嗯嗯..我想我失去了真正的问题..我修正了我的答案。【参考方案2】:

这是一个可能的解决方案,但我不相信它始终有效。我相信它适用于 NUL 文件描述符的特定情况:

int real_isatty(int fd) DWORD st; 处理 h; 如果(!_isatty(fd)) /* TTY 必须是字符设备 */ 返回0; h = (句柄)_get_osfhandle(fd); 如果(h == INVALID_HANDLE_VALUE) /* 损坏的句柄不能是终端 */ 返回0; if (!GetConsoleMode(h, &st)) /* GetConsoleMode 在不是 TTY 时似乎失败。 */ 返回0; 返回 1;

【讨论】:

【参考方案3】:

您可以在文件描述符上使用fstat,并将生成的stat 结构的设备成员与/dev/null 的设备成员进行比较,看看它们是否匹配。

【讨论】:

不起作用。 _stat 总是返回 2,而 _fstat 总是返回 0。

以上是关于检测 NUL 文件描述符(isatty 是假的)的主要内容,如果未能解决你的问题,请参考以下文章

为啥 Object.prototype instanceof Object 是假的?

在啥情况下 websocket 关闭事件会告诉你 wasClean 是假的?

进入while循环,即使它是假的

(x || !x) 啥时候是假的?

为啥 type(nil)==nil 是假的?

黄仁勋骗过了全世界,三个多月都没人发觉!皮衣是假的厨房是假的,连他自己都是假的...