cat 会破坏程序,手动 stdin 输入不会

标签 c shell fork stdin cat

我有这个小程序:

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/wait.h>

int main() {
    int orig = 1;
    for (int i = 0; (i != 3) && orig; ++i) {
        orig = orig && fork();
    }
    if (orig) {
        for (int i = 0; i != 3; ++i) {
            wait(NULL);
        }
    } else {
        int num;
        scanf("%8d", &num);
        printf("%d\n", num*num);
    }
}

它应该简单地计算从 stdin 读取的三个数字的平方。如果我自己输入数字,它就会起作用:

akiiino$ ./out.out
12345678
12345678
12345678
260846532
260846532
260846532

但是如果我将 cat 用于相同的目的,它不会按预期工作:

akiiino$ cat in.txt
12345678
12345678
12345678

akiiino$ cat in.txt | ./out.out
260846532
0
0

这种奇怪行为背后的原因是什么?可以修复吗?我一直认为cat文件与将它们输入stdin没有什么不同。

最佳答案

不同之处在于,当您手动输入 3 个数字时,您正在从终端读取数据,并且低级读取会在换行符处终止。让我们看看幕后发生了什么。

  1. 手动输入:

    • 3 个 child 已经开始并正在等待输入
    • 您输入一个数字和一个新行
    • 底层 read 调用由换行符终止,因为您从终端读取
    • 第一个 child (获得读取的 child )的 scanf 调用对输入进行解码并进行处理

    好的,我们对另外 2 个 child 进行同样的操作

  2. 从文件或管道中读取

    • 3 个 child 已经开始并正在等待输入
    • 这 3 个数字和换行符立即可用
    • 第一个子进程的底层read读取并消耗stdio缓冲区中的所有输入
    • 第一个 child (获得读取的 child )的 scanf 调用对输入(第一部分)进行解码并进行处理

    但是现在另外 2 个 child 正在从位于文件末尾的文件/管道中读取。他们的 scanf 返回 0 但你无法控制它,他们让 num 中初始未确定的值。

您可以通过在循环之前添加 sleep(10) 来控制这不是竞争条件问题,在第一个子级开始读取之前启动程序并手动输入 3 个数字。由于低级读取将以换行符终止(特殊的 tty 情况),即使 3 行在第一次读取之前可用,您仍然会得到与第一种情况相同的输出。

关于cat 会破坏程序,手动 stdin 输入不会,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/43278397/

相关文章:

c - 当我将文件传递到链接列表时,如何读取文件并确定其数据表示形式?

c++ - 如何在 C 或 C++ 中从命令行读取多行输入?

c - 我是否需要在 fork 之后在父进程中等待()?

c - 我的 fork() 从不等于 0

c - 如何从第二个访问第一个结构-c

c - 为什么 macOS 上 C 中的 execve 命令不允许 'which' 命令起作用?

shell - 如何找出shell中是否存在shell命令

linux - 是否可以检查unix中的下一行是否包含一行,如果是,则删除下一行

bash - 检测单色图像中最右边黑色像素的 x 值?

c - Unix 分支 : how many processes are created?