带重定向的stdin上的C系统行为

带重定向的stdin上的C系统行为,c,fork,system,stdin,file-descriptor,C,Fork,System,Stdin,File Descriptor,我正在玩一些系统函数和文件重定向,发现了一个奇怪的行为,我真的不明白 我有一个读取stdin的第一个进程,然后在另一个也读取stdin的进程上使用fork(调用系统函数) 在第一种情况下,我没有将任何内容重定向到第一个进程的stdin,所有内容都按预期工作,两个进程都从我的提示符读取 但在第二种情况下,我将一个文件管道化或重定向到第一个进程,分叉的进程开始读取“随机”数据 以下是我的模拟示例: 叉子 #include <stdlib.h> #include <stdio.h&g

我正在玩一些系统函数和文件重定向,发现了一个奇怪的行为,我真的不明白

我有一个读取stdin的第一个进程,然后在另一个也读取stdin的进程上使用fork(调用系统函数)

在第一种情况下,我没有将任何内容重定向到第一个进程的stdin,所有内容都按预期工作,两个进程都从我的提示符读取

但在第二种情况下,我将一个文件管道化或重定向到第一个进程,分叉的进程开始读取“随机”数据

以下是我的模拟示例:

叉子

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

int main() {
    char buf[10];
    fgets(buf,10,stdin);
    printf("Buff: %s\n", buf);
    system("./print");
    fgets(buf,10,stdin);
    printf("Buff: %s\n", buf);
    return 0;
}
我明白了

对于孩子来说,输入总是不同的(我猜它是在读取内存中的某个随机位置…)

有人能解释这种行为吗?我知道孩子在fork上继承了文件描述符,但我不明白为什么它不能读取与父母相同的输入,或者至少是确定性的输入


我想知道在调用我的fork程序时,是否有一个技巧来表示我希望“fork”有这个输入,而它的子进程有另一个输入。

您应该查看子进程中的
fgets()
返回的错误状态,并在
fgets()报告它时报告EOF

父进程已经从管道中读取了一个装满信息的缓冲区,并将以9个字符+空字节的增量进行分配。由于信息已经从管道中消失,孩子无法阅读任何内容并报告EOF。父对象继续使用其缓冲输入中的材质

始终检查I/O调用(尤其是输入调用)是否成功

叉子
#包括
#包括
内部主(空)
{
char-buf[10];
如果(fgets(buf,10,stdin)!=0)
printf(“Buff-1:%s\n”,buf);
其他的
printf(“Buff-1:检测到EOF\n”);
系统(“/打印”);
如果(fgets(buf,10,stdin)!=0)
printf(“Buff-2:%s\n”,buf);
其他的
printf(“Buff-2:检测到EOF\n”);
返回0;
}
打印
#包括
内部主(空)
{
char-buf[10];
如果(fgets(buf,10,stdin)!=0)
printf(“Buff-C:%s\n”,buf);
其他的
printf(“Buff-C:\n”);
返回0;
}
样本运行 在第一次运行时,我在键盘上键入输入。打印“similitud”后,系统似乎挂起,因此我键入了“miscellaneous”,子进程报告了“miscellan”(如果它继续阅读,本可以报告“Eouse”)。同时,父进程继续报告来自“ude”行的数据

在第二个示例中,正如预测的那样,子进程报告了EOF,因为父进程在其第一个输入操作中读取了管道中的所有数据

$ ./fork
similitude and gratitude and attitude and longitude, dude!
Buff-1: similitud
miscellaneous
Buff-C: miscellan
Buff-2: e and gra
$ echo "just another awesome input" | ./fork
Buff-1: just anot
Buff-C: <<EOF>>
Buff-2: her aweso
$
$。/fork
相似、感激、态度和经度,伙计!
Buff-1:相似
混杂的
Buff-C:杂项
Buff-2:e和gra
$echo“又一个很棒的输入”|/fork
Buff-1:再做一次
Buff-C:
Buff-2:她的敬畏
$

完成乔纳森的回答

这个孩子确实收到了EOF。原因是父级读取的不仅仅是fgets请求。Strace显示父级读取4096字节的块。 因此,如果要将一些数据直接传递给子进程,只需在4096个字节后写入

例如

另一个有趣的方法是使用cat读取提示符

$ (echo "once upon a time";cat) | ./fork
Buff: once upon
test               <-- I am prompted here
Buff: test

Buff:  a time
$(回显“曾几何时”猫)|。/fork
牛:从前

测试Q:你能给我们看一下fork()(大概还有后续的exec())吗?fork是由系统(
system(“./print”);
在我的代码中完成的。从
man系统
,它是这样分叉执行shell的:
execl(“/bin/sh”,“sh”,“-c”,command,(char*)0),因此它接收的io流完全不同。查看system.c和man exec后,execl不会对文件描述符进行任何更改。看看strace,父母似乎一次就消耗了全部输入,这就解释了为什么孩子不能阅读它。但是我想知道是否有一种方法可以将某些内容传递给孩子(而不改变C代码)。
Buff: just anot
Buff: Ðhuÿ
Buff: her aweso
#include <stdlib.h>
#include <stdio.h>

int main(void)
{
    char buf[10];
    if (fgets(buf,10,stdin) != 0)
      printf("Buff-1: %s\n", buf);
    else
      printf("Buff-1: EOF detected\n");
    system("./print");
    if (fgets(buf,10,stdin) != 0)
      printf("Buff-2: %s\n", buf);
    else
      printf("Buff-2: EOF detected\n");
    return 0;
}
#include <stdio.h>

int main(void)
{
    char buf[10];
    if (fgets(buf,10,stdin) != 0)
      printf("Buff-C: %s\n", buf);
    else
      printf("Buff-C: <<EOF>>\n");
    return 0;
}
$ ./fork
similitude and gratitude and attitude and longitude, dude!
Buff-1: similitud
miscellaneous
Buff-C: miscellan
Buff-2: e and gra
$ echo "just another awesome input" | ./fork
Buff-1: just anot
Buff-C: <<EOF>>
Buff-2: her aweso
$
$ python -c 'print "0*4096"+"123"' | ./fork
Buff: 0000000000
Buff: 123

Buff: 0000000000
$ (echo "once upon a time";cat) | ./fork
Buff: once upon
test               <-- I am prompted here
Buff: test

Buff:  a time