无法从C中的stdin / STDIN_FILENO读取输入?

时间:2018-05-03 06:10:00

标签: c stdin stdio

我有这个命令行参数 -

cat file_name | ./a.out 

问题不在于读取C程序中的cat命令,因为我们可以使用read()fgets()fgetc()来解决这个问题,但我遇到的实际问题是在阅读之后来自cat的数据我无法使用fgets从用户那里获取输入信息。

这是我的示例代码

while(fgets(buffer, BUFSIZ, stdin ) != NULL )
    puts( buffer ); // Here I have tried strtok( buffer, "\n" ) too.
memset( buffer, 0, BUFSIZ );`

问题出在这一行之后,它不是要求输入如下所示 -

puts("Name: ");
fgets( buffer, BUFSIZ, stdin );

帮助我解决这里发生的错误?

2 个答案:

答案 0 :(得分:1)

执行cat file_name | ./a.out时,程序的标准输入与将其链接到cat输出的管道相关联。您的程序永远不会看到用户输入 - 它到达的流已被上述管道取代。

请注意,我怀疑使用一些可怕的POSIX特定技巧你可以重新打开它直接用于tty设备,但这只是糟糕的设计。如果您需要同时读取文件接受交互式用户输入,只需将该文件作为命令行参数接受,并使用stdin与用户进行交互。

修改

这是一个可以尝试的特定于Unix的kludges的示例,假设该进程仍然具有控制终端。在读完所有原始标准输入后,我打开/dev/tty(这是该过程的控制终端)并重新链接stdin

免责声明:这仅用于娱乐目的, 不要用于真实

#include <stdio.h>
#include <stdlib.h>

void die(const char *msg) {
    fprintf(stderr, "%s\n", msg);
    fputs(msg, stderr);
    exit(1);
}

int main() {
    /* Read all of stdin and count the bytes read (just to do something with it) */
    int ch;
    unsigned long count = 0;
    while((ch = getchar())!=EOF) {
        count++;
    }
    printf("Read %lu bytes from stdin\n", count);
    /* Open the controlling terminal and re-link it to the relevant C library FILE *
     * Notice that the UNIX fd for stdin is still the old one (it's
     * surprisingly complex to "reset" stdio stdin to a new UNIX fd) */
    if(freopen("/dev/tty", "r", stdin) == NULL) {
        die("Failed freopen");
    }

    /* Do something with this newly gained console */
    puts("How old are you?");
    fflush(stdout);
    int age = -1;
    if(scanf("%d", &age)!=1) {
        die("Bad input");
    }
    printf("You are %d years old\n", age);
    return 0;
}

(之前我有一个解决方案,检查stderrstdout是否仍然是游戏机,这更像是一个kludge;感谢 @rici 提醒我事实上,POSIX具有“控制终端”的概念,可以通过/dev/tty

访问

答案 1 :(得分:0)

如果您需要使用stdin进行用户交互,则需要使用不同的文件描述符来读取输入流。

您可以使用特定的预打开文件描述符和文档(例如&#34; 输入流应该连接到fd 3 &#34;),但通常的方法是接受文件名作为命令行参数。然后,您可以提供命名管道作为参数;像Bash这样的shell提供了进程替换来简化:

./a.out <(cat file_name)

当交互式运行时,stdin仍然连接到终端,并且可以与来自连接命令的流同时使用。

(显然,如果命令实际 cat只有一个参数,那么你可以只提供文件名本身作为参数,但我假设&#39; m ;一个占位面积较大的管道​​)。