2015-04-04 30 views
2

我正在开发一个类似Unix的“更多”命令的C项目。像“更多”一样,如果没有给出文件(因此可以将其他程序的输出传送给它)并将其显示到标准输出,则该程序应该能够从文件(如果指定)或标准输入中获得输入。另外像“更多”,呼应和规范模式都应该被禁止,我已经用下面的代码完成:C:从Stdin读取重置终端属性?

//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 

读取从键盘,我打开“开发/ 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接收输入,似乎终端属性被重置。我可以看到我尝试键入的每个命令(这意味着再次显示回显),并且命令不会发送到程序,除非我按下Enter键(意味着规范模式已经以某种方式再次被重新激活)。我在网上搜索了几乎所有的系统调用手册,并且似乎无法找到原因。

如果有人知道为什么会发生这种情况,以及如何解决它,帮助将不胜感激。

谢谢!

+1

你的评论说“改变终端属性”,但这不是你在做什么。您正在更改文件描述符零的属性,当您将标准输入重定向为从文件中读取时,它不是终端! – 2015-04-04 16:45:02

+0

您应该检查'tcgetattr()'和'tcsetattr()'的返回值。您不会说代码是通过文件('yourprog 2015-04-04 17:18:31

回答

3

什么似乎缺失(至少在问题中没有说明)是,您打开/dev/tty来读取命令,并通过文件描述符重置原始标准输入。但没有提及使用fdreopendup2的:

  • ,因为你是指文件描述符0(FILENO_STDIN),这是不一样的文件描述符fileno(cmd) - 除非你使用dup2来替换。
  • 通常会使用open而不是fopen打开设备,只是因为open提供了对该过程的更多控制。然后使用fdreopen从文件描述符中获取缓冲流。

使用上/dev/ttyfopen,例如,你可能已经在流,这是不一定相同,你文件描述符0重新忽视的实际设置。相关的问题可能是:What is the difference between stdin and STDIN_FILENO?