【问题标题】:How to flush stdin without requiring user input? [duplicate]如何在不需要用户输入的情况下刷新标准输入? [复制]
【发布时间】:2026-02-12 12:55:02
【问题描述】:

我正在尝试模拟命令行 shell。用户输入他们想要输入的 shell 命令,例如/bin/pwd 和代码是为了执行它。

缓冲区设置为读取固定数量的字符(例如 20 个)。

如果用户输入超过 20 个字符,则需要在 shell 再次循环之前刷新多余的字符。

我一直在尝试这样做:

int garbageCollector; 
while ((garbageCollector = getchar()) != '\n' && garbageCollector != EOF);

但问题是getChar()要求你先输入一个字符。

有没有一种不需要用户输入任何内容来刷新标准输入的方法?

while (1) {

    // Prompt user for input
    ssize_t readIn = read(STDIN_FILENO, buffer, BUF_SIZE + 1);
    if (readIn < 0) {
        perror("read() failed");
        return 2;
    } 

    // Null-terminate and remove line return
    buffer[readIn - 1] = '\0'; 

    char program[strlen(buffer)];
    strcpy(program, buffer);
    printf("program is: %s\n", program);

    // Flush stdin
    int garbageCollector; 
    while ((garbageCollector = getchar()) != '\n' && garbageCollector != EOF);

    // Create child process
    child = fork();
    if (child < 0) {
        perror("fork() failed");
        return 3;
    }

    // Start alarm that is triggered after timeout exceeded
    // which then kills child process
    signal(SIGALRM, killChild);
    alarm(timeout); 

    if (child == 0) { // Child
        char* av[] = { program, NULL };
        execve(program, av, NULL);  

    } else {  // Parent
        wait(NULL);
        alarm(0);  // Reset alarm if program executed
    }

    memset(buffer, 0, BUF_SIZE); // Flush buffer
}

【问题讨论】:

  • 请注意,20 个字符的命令行在中期是不可行的——它太短了。 2000 个字符,也许你会在竞选中。
  • 像 Bash 这样的 Shell 将终端置于非规范模式并使用该模式读取 - 不使用标准 I/O 函数。它更类似于使用 Curses 库。
  • 是的,20 个字符只是一个例子。如何在没有标准 I/O 功能的情况下刷新缓冲区?

标签: c stdin flush


【解决方案1】:

相关问题中的某个人建议这样做:

fseek(stdin,0,SEEK_END);

似乎适用于 Mac 和 Windows,但不适用于 Linux。对于 Linux,Daniel 的建议有效:

fflush(stdin);

因此,您可以在编译时解决此问题,并根据您正在编译的操作系统使用fflushfseek

#ifdef defined(_WIN32) || defined(__APPLE__)
  #define flush_stdin(stdin) fseek(stdin,0,SEEK_END)
#elif defined(__linux__) || defined(__unix__)
  #define flush_stdin(stdin) fflush(stdin)
#else
  #define flush_stdin(...) UNIMPLEMENTED

【讨论】:

  • 谢谢。顺便说一句——如果我只使用系统调用,即没有像 fflush 和 fseek 这样的库函数,那么我该如何实现呢?
  • @doctopus 我对 craig 的解决方案投了赞成票,因为它更好,并且可以在 *nix / osx 上运行。如果您需要在 Windows 上执行此操作,请使用fflush,即使您通过了stdin,它也能满足您的要求。 fflush 显然是 *nix/osx 上的 UB,但实施相当广泛。
  • @doctopus 虽然,我认为底部的注释没有任何问题。在 EOF 之前调用 read 将在任何地方工作。
  • 当我在底部实现你的代码时,它让我进入一个无限循环,不断提示用户输入@okovko
  • @doctopus 没关系,我不知道我在想什么。需要睡眠。 :P
【解决方案2】:

如果非 POSIX 可移植性不是问题(请注意,这不适用于 Windows - 但我看到您使用的 fork() 也不适用于 Windows),您可以暂时将文件描述符设置为重新尝试刷新非阻塞并从中读取所有输入:

int flush_in(FILE *file)
{
    int ch;
    int flags;
    int fd;

    fd = fileno(file);
    flags = fcntl(fd, F_GETFL, 0);
    if (flags < 0) {
        return -1;
    }
    if (fcntl(fd, F_SETFL, flags | O_NONBLOCK)) {
        return -1;
    }
    do {
        ch = fgetc(file);
    } while (ch != EOF);
    clearerr(file);
    if (fcntl(fd, F_SETFL, flags)) {
        return -1;
    }
    return 0;
}

然后你会打电话给flush_in(stdin)

【讨论】:

    最近更新 更多