【问题标题】:piped stdin and keyboard same time in C在 C 中同时管道标准输入和键盘
【发布时间】:2015-04-17 02:10:57
【问题描述】:

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

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

    return 0;
}  

我想从文件中读取数据,该文件作为 pipied stding 传递给程序

程序
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 方法和管道标准输入程序工作正常。 我无法解决这个问题,有人有想法吗..

【问题讨论】:

  • 根据您的具体需要,您可以通过将管道输入和终端输入与 && 运算符相结合来解决此问题 - 请参阅 stackoverflow.com/questions/5843741/…
  • 谢谢你 我从来不知道我不能同时做这两件事。你有什么好的参考资料可以让我了解更多关于管道和标准输入的信息,这有助于我理解这个问题。为什么会这样?

标签: c stdin


【解决方案1】:

管道通常位于文件描述符0 上(由shell 控制),这是标准输入。您可以使用dup2() 将其“移动”到不同的文件描述符,并使用freopen() 继续从中读取。您还可以打开/dev/tty 设备(或tty 程序知道的任何东西)并将那个设置为您的标准输入。

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

--input-fd fd

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

实现这一点的逻辑在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);
    }

【讨论】:

    【解决方案2】:

    我编写的程序从stdin(从其他程序的stdout 导入)读取二进制数据的程序几乎相同,但我想添加键盘命令(通过raw terminal support)。显然,同时读取管道数据和键盘会导致一些奇怪的结果。

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

    文件 * fp; 诠释 fd; fd = dup(fileno(stdin)); fp = fdopen(fd, "r"); (void) freopen("/dev/tty", "r", 标准输入);

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

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

    【讨论】:

    • P.S.我的意思是感谢 Thomas 的回答——我自己的回答只是添加另一个简单的例子来做 Krv(和我自己)需要做的事情。
    【解决方案3】:

    如果你想让你的程序接受键盘输入,那么不要重定向它的标准输入。如果您重定向程序的标准输入,不要期望能够通过键盘为其提供数据。

    如果您的程序需要同时接受来自文件和键盘的输入,则将文件名作为参数提供给它,并让它打开并读取该文件。

    如果您必须处理需要通过stdin 提供输入的某种不可修改的库函数,并且您希望该输入来自文件,并且 em> 你想在其他地方接受键盘输入,那么你可以用dup2()ing 文件描述符玩游戏来解决问题。一旦你得到它的工作,考虑解雇负责该库功能的白痴。

    【讨论】:

      猜你喜欢
      • 2012-02-23
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2014-06-03
      • 1970-01-01
      • 1970-01-01
      • 2015-12-16
      • 2016-04-26
      相关资源
      最近更新 更多