【问题标题】:How to restart stdin after Ctrl+D?Ctrl+D后如何重启stdin?
【发布时间】:2018-07-05 15:14:50
【问题描述】:

运行一个期望终端输入的程序,我可以通过 Ctrl+D“关闭”标准输入。之后有没有办法重新打开标准输入?

【问题讨论】:

  • 你可以 fopen("/dev/tty", "r")
  • 不是'重新打开标准输入',但我相信你真正想要的。
  • 我发现一个简单的clearerr(stdin) 在这种情况下通常就足够了。
  • freopen("/dev/tty", "r", stdin)
  • @PSkocik:已编辑 nitpick:改为使用 char buf[32]; for (;;) printf("read=%zd\n", read(0, buf, sizeof buf));。 (我只是习惯于编写STDIN_FILENO 示例代码,我什至没有注意到我更改了那部分。我的意思是使用%zd 代替ssize_t。)

标签: c linux


【解决方案1】:

和一般的POSIXy 系统上,当您在终端中按Ctrl+D 时,标准输入描述符不会关闭;它只是使伪终端层变得可读,read() 返回 0。这就是 POSIXy 系统指示输入结束的方式。

这并不意味着文件描述符(甚至是 C 库在其之上提供的流句柄)被关闭。正如 Steve Summit 在评论中提到的,您只需要使用clearerr()清除流的输入结束状态,以便能够读取更多数据;这告诉 C 库您注意到了状态变化,但还是想尝试进一步阅读。

当一个进程正在写入文件,而另一个进程读取它时,可能会发生类似的情况。当阅读器到达文件末尾时,read() 返回 0,C 库将其理解为输入结束;它设置了一个内部标志,因此除非您调用clearerr(),否则feof() 将为该流返回true。现在,如果 writer 写入更多数据,而 reader 执行 clearerr(),则 reader 可以读取新写入的附加数据。

这是完全正常的预期行为。

总结:

  • read() 操作返回 0 表示输入结束,但文件描述符状态没有改变,可以正常使用。

  • Ctrl+D 在终端上只会导致这种情况发生;对终端打开的文件描述符不会以任何其他方式受到影响,由前台进程读取终端输入来决定它的作用。允许简单地继续读取更多数据。

    当这种情况发生时,大多数程序都会退出,但这是约定俗成的,根本不是技术要求。

  • C 库检测到 read() 返回 0,并为该流设置其内部“输入结束”标志。对于该流,这会导致 feof() 返回 true,fgets() 返回 NULL,fgetc() 返回 EOF,依此类推。

  • 在流句柄上调用clearerr() 会清除该标志,因此下一次读取尝试实际上会尝试从描述符中读取更多数据。

    这在man 3 clearerr 手册页的描述部分的第一句话中进行了描述。

【讨论】:

  • 我认为不需要示例程序。如果您认为它对多个读者有用,我可以挑一两个。
  • 另一个例子是随机访问。如果你读过了EOF,然后更清楚并在里面寻找,那么你可以重新开始阅读。
  • @GemTaylor:如果您执行fseek(stream, bytes, SEEK_SET)fseek(stream, -bytes, SEEK_CUR)fseek(stream, -bytes, SEEK_END),在文件中向后搜索,它也会清除流结束标志;也无需致电clearerr()
  • 甚至更好:-) 它仍然证明了 EOF 并不意味着 istream/FILE*/handle 已失效的原理。寻找相对0是否清楚? :-)
  • @GemTaylor:是的。 fseek() 清除内部文件结束标志,除非它失败。 (你不能寻找管道和套接字。如果stream 引用了一个同时没有被截断的文件,那么fseek(stream, 0, SEEK_END)fseek(stream, 0, SEEK_CUR) 都成功了,清除了内部文件结束标志。)
猜你喜欢
  • 2015-12-03
  • 1970-01-01
  • 2014-02-11
  • 2013-03-17
  • 1970-01-01
  • 1970-01-01
  • 2018-12-25
  • 1970-01-01
相关资源
最近更新 更多