我正在开发一个类似于Unix的“更多”命令的C项目。就像“更多”一样,这个程序应该能够从文件(如果指定)或stdin获取其输入(如果没有给出文件)(因此其他程序的输出可以通过管道输入)并将其显示到stdout。也喜欢“更多”,应该禁用回声和规范模式,我已经用以下代码完成了:
//change terminal attributes
tcgetattr(0, &info); //Get info
tcgetattr(0, &orig_inf); //Save original info
info.c_lflag &= ~ECHO; //Disable echo
info.c_lflag &= ~ICANON; //Disable canonical mode
info.c_cc[VMIN] = 1; //Get 1 char at a time
tcsetattr(0, TCSANOW, &info); //Set attributes
要从键盘读取用户命令,我显式打开“dev / tty”而不是只读取stdin:
//Open cmd stream
if((cmd = fopen("/dev/tty", "r")) == NULL){
perror("Failure opening command stream");
tcsetattr(0, TCSANOW, &orig_inf);
exit(EXIT_FAILURE);
}
用getc(cmd)读取它们。当用户提供要读取的文件时,这可以正常工作,但如果程序正在从stdin接收输入,则似乎正在重置终端属性。我可以看到我尝试输入的每个命令(这意味着回显再次打开)并且命令不会被发送到程序,除非我点击输入(意味着规范模式已经以某种方式再次被重新激活)。我搜索了网络和所有手册页几乎所有我正在使用的系统调用,似乎无法找到原因。
如果有人知道为什么会发生这种情况以及如何解决这个问题,那将非常感谢帮助。
谢谢!
答案 0 :(得分:3)
似乎缺少的内容(至少在问题中未说明)是您正在打开/dev/tty
来读取命令,并通过文件描述符重置原始标准输入。但是没有提到使用fdreopen
或dup2
:
0
(FILENO_STDIN),这与fileno(cmd)
不是同一个文件描述符 - 除非您使用dup2
替换它。open
而不是fopen
打开设备,因为open
可以更好地控制流程。然后,可以使用fdreopen
从文件描述符中获取缓冲流。在fopen
上使用/dev/tty
,您可能忽略了 流中的实际设置,这些设置不一定与您在文件中重新配置的设置相同描述符0
。相关问题可能是:What is the difference between stdin and STDIN_FILENO?。