C语言如何先读取stdin重定向或管道内容,再读取键盘输入
问题根因
- 当使用
program < test.txt重定向或管道传入内容运行程序时,进程的标准输入(stdin)默认绑定的是传入的文件/管道,而非当前控制终端。读完所有传入内容后,stdin流会被标记为EOF,后续所有读取stdin的操作都会直接返回EOF,不会响应键盘输入。 - 仅调用
clearerr(stdin)清除EOF标记无法解决问题,因为此时stdin的数据源仍然是已经读完的文件/管道,并没有绑定到键盘对应的终端设备。
可行解决方案
方案1:将stdin重新绑定到控制终端(最小修改原有代码)
类Unix系统(Linux/macOS)下可以通过freopen将stdin重新关联到当前进程的控制终端/dev/tty,修改后的代码如下:
#include <stdio.h> #include <unistd.h> int main() { int ch; // 读取重定向/管道传入的内容 while (EOF != (ch = getchar())) { printf("%c", ch); } sleep(3); // 新增:将stdin重新绑定到控制终端 if (freopen("/dev/tty", "r", stdin) == NULL) { perror("无法打开控制终端"); return 1; } // 后续getchar就可以正常读取键盘输入 while (1) { while ('\n' != (ch = getchar())) { if (ch == EOF) break; // 处理终端输入的EOF(Ctrl+D) printf("%c", ch); } putchar('\n'); // 补充换行符对齐输出 } return 0; }
Windows平台可以将/dev/tty替换为CON实现相同效果。
方案2:单独打开终端流读取键盘输入
如果不想修改原有stdin的绑定,可以单独打开控制终端的文件指针,专门用于读取键盘输入:
// 定义专门读取终端的文件指针 FILE *tty = fopen("/dev/tty", "r"); if (!tty) { perror("无法打开控制终端"); return 1; } // 后续读取键盘用fgetc(tty)替代getchar即可
注意事项
如果程序运行在没有控制终端的环境(例如systemd服务、后台无终端启动的进程),打开/dev/tty会失败,这种场景下本身就不存在键盘输入源,需根据业务逻辑做异常处理。
内容的提问来源于stack exchange,提问作者Pete Mitchell
相关产品推荐
相关产品推荐

