管道stdin和键盘同时在C

时间:2015-04-17 02:10:58

标签: c stdin

我也已经阅读过有关此问题的先前问题。 fflush(stdin)对我来说在这种情况下不起作用。 我希望我的程序从管道标准输入读取,并从中间的键盘输入继续。

int main()
{
    int userin = 3;
    read_input();   
    userin = print_menu();
    userin = parse_input(userin);

    return 0;
}  

我想从文件中读取数据,该文件作为像

这样的pipied stding传递给程序

程序< testing_text

int read_input(){
    char line[200];
    char word[MAX_STRING+1];
    int line_number = 0;

    while(fgets(line, sizeof(line), stdin) != NULL ){
        //do something
        printf("%s",line); 
        line_number++;
    }
}

现在read_input必须从管道输入完成读取。 ' print_menu'必须继续从键盘上读取。

int print_menu()
{
    int userinput;
    char c;
    char num[4];
    while((c=getchar()) != '\n' && c != EOF && c != '\r');

    printf("\n1. Choice 1 \n");
    printf("2. Choice 2\n");
    printf("3. Exit\n");
    printf("Enter your choice (1-3): ");

   /* scanf("%d", &userinput); */
   /* fgets(num,80,stdin);  */

   scanf("%s", num);
   userinput = atoi(num);   
   return userinput;
}

int parse_input(int userinput)
{
    char num[4];
    while( userinput > 3 || userinput < 1 ){
       printf("Sorry, that is not a valid option\n");
       printf("Enter your choice (1-3): ");
       scanf("%s", num);
       userinput = atoi(num);

       /* scanf("%d", &userinput); */
       /* while( (c = getchar()) == '\n'); */
    }
     return userinput;
}

我的输出是

的无限循环
Enter your choice (1-3): Sorry, that is not a valid option

当我删除read_input方法和管道stdin程序工作正常。 我无法弄清楚这个,有人有想法......

3 个答案:

答案 0 :(得分:3)

管道(通常由shell控制)通常在文件描述符0上,这是标准输入。您可以使用dup2()来&#34;移动&#34;对于不同的文件描述符,并使用freopen()继续读取它。您也可以打开/dev/tty设备(或tty程序知道的任何设备),然后 您的标准输入。

dialog程序为--gauge(进度条)选项执行此操作。它之所以这样做是因为对话框是curses应用程序(默认情况下使用标准输入和输出)。实际的管道文件描述符也是可选的,因此从manual page引用会给出一些提示:

  

- input-fd fd

     

从给定文件描述符中读取键盘输入。大多数对话框   脚本从标准输入读取,但仪表小部件读取   管道(始终是标准输入)。有些配置可以   对话框尝试重新打开终端时无法正常工作。使用   这个选项(有适当的文件描述符杂耍)if   您的脚本必须在这种类型的环境中工作。

实现此目的的逻辑位于util.c,来自init_dialog函数。以下是其中的主要部分,以了解如何使用这些函数:

    dialog_state.pipe_input = stdin;
    if (fileno(input) != fileno(stdin)) {
        if ((fd1 = dup(fileno(input))) >= 0
            && (fd2 = dup(fileno(stdin))) >= 0) {
            (void) dup2(fileno(input), fileno(stdin));
            dialog_state.pipe_input = fdopen(fd2, "r");
            if (fileno(stdin) != 0)     /* some functions may read fd #0 */
                (void) dup2(fileno(stdin), 0);
        } else {
            dlg_exiterr("cannot open tty-input");
        }
        close(fd1);
    } else if (!isatty(fileno(stdin))) {
        if ((fd1 = open_terminal(&device, O_RDONLY)) >= 0) {
            if ((fd2 = dup(fileno(stdin))) >= 0) {
                dialog_state.pipe_input = fdopen(fd2, "r");
                if (freopen(device, "r", stdin) == 0)
                    dlg_exiterr("cannot open tty-input");
                if (fileno(stdin) != 0)         /* some functions may read fd #0 */
                    (void) dup2(fileno(stdin), 0);
            }
            close(fd1);
        }
        free(device);
    }

答案 1 :(得分:1)

如果您希望程序接受键盘输入,请不要重定向其标准输入。如果您重定向程序的标准输入,请不要期望能够通过键盘提供数据。

如果你的程序需要接受来自文件和键盘的输入,那么给它作为参数的文件名,让它打开并读取该文件。

如果你必须处理需要通过stdin提供输入的某种不可修改的库函数,你希望输入来自一个文件,你想在其他地方接受键盘输入,然后你可以用dup2()文件描述符来玩游戏,让它运行起来。一旦你开始工作,考虑解雇负责该库功能的白痴。

答案 2 :(得分:1)

我写的一个程序与stdin读取二进制数据(从其他程序的stdout管道输入)的情况几乎相同,但是我想添加键盘命令(通过{{ 3}})。显然,同时阅读管道数据和键盘会导致一些奇怪的结果。

这是我的代码,工作和测试:

FILE * fp;
int fd;

fd = dup(fileno(stdin));
fp = fdopen(fd, "r");
(void) freopen("/dev/tty", "r", stdin);

现在,我的程序从fp(一个FILE*对象)读取其二进制数据,同时读取stdin(现在与"/dev/tty"关联)以进行击键。

请注意,我会从freopenFILE*对象)中丢弃返回值,因为如果需要,我可以通过stdin引用它。我的经验是,无需close()fclose()标准文本流。我在阅读二进制数据结束时fclose(fp)