【问题标题】:How to check stdin is empty with no hang?如何检查标准输入是否为空且没有挂起?
【发布时间】:2021-01-12 16:32:46
【问题描述】:

我希望我的程序从命令行选项或标准输入(重定向)读取数据。那么如何检查stdin是否为空呢?

如果stdin 为空(等待输入),则执行fgetc 会挂起我的程序。调用 feof 返回 false。

也试过了

ioctl(0, I_NREAD, &n) == 0 && n > 0

但我没有定义 I_NREAD(在 Raspi 上,但我想要便携)。

如何实现?

【问题讨论】:

  • 没有这个概念。 stdin 只是一个流,或者您处于流的末尾(当它关闭时会发生这种情况 - 例如,如果您按 ctrl-D 或如果您从文件重定向标准输入)。如果你想处理终端对象(不是stdin),你必须放弃标准输入并为此使用适当的API(打开控制终端设备/dev/tty)。
  • 所以写程序是不可能的,感觉是不是被重定向喂了?
  • 它总是被重定向。当您直接与其交互时,它(通常)从 pty 重定向。您可以通过isatty(STDIN_FILENO) 进行检查。
  • 我不知道这是否与您相关,但规范的 unix 工具会反过来:在命令行上查找参数,如果没有提供输入,则使用 stdin在争论中。例如cat foo 将读取foo,但cat 将从标准输入读取。
  • 就像spectras 所说的,Unix 命令行工具在缺少任何要处理的文件时会查找标准输入。但除此之外,他们通常将单个减号视为标准输入的文件名。因此,如果您输入 cat -,您将得到与 cat 相同的结果

标签: c stdin


【解决方案1】:

select 函数可以在 POSIX 系统上完成。在 Windows 或其他系统上,您需要其他选项。

请注意,如果 shell 设置了管道并且操作系统安排子进程首先运行(first | child),它可能会执行选择并且找不到任何准备读取的输入。

请注意,我将超时从 0 更改为 100,000 微秒(0.1 秒),这有助于避免随机丢失输入。但是,如果系统负载过重,它仍然可能无法检测到标准输入已准备好读取。

见:

#include <stdio.h>
#include <sys/select.h>

int main() {
  fd_set read_fds;
  struct timeval tv = {0, 100000};
  int fd = fileno(stdin);
  int r;

  FD_ZERO(&read_fds);
  FD_SET(fd, &read_fds);
  r = select(fd + 1, &read_fds, NULL, NULL, &tv);
  if (r > 0) {
    char buffer[256];
    if (fgets(buffer, 256, stdin)) {
      puts(buffer);
    }
  }
  return 0;
}

【讨论】:

  • 请注意,这样做会在很多方面破坏程序(从用户的角度来看)。例如,otherprog | yourprog 有时会看到来自 otherprog 的输入,有时则不会,这取决于调度顺序等因素。
  • @spectras 嗯。是的,你是对的。也许使用更高的超时值会有所帮助,但如果系统处于极端负载和/或交换状态,并且首先安排子节点仍然可能失败。
猜你喜欢
  • 2012-02-04
  • 1970-01-01
  • 2019-11-15
  • 1970-01-01
  • 2012-02-03
  • 2015-08-10
  • 2016-07-30
  • 2021-11-22
  • 2011-04-15
相关资源
最近更新 更多