我正在创建一个子父级fork()
,以便能够通过管道与父级(/bin/sh
)进行通信。
问题是:
在父级中,我在子输出上设置了select()
,但只有在进程完成时才会解锁!所以,当我说ps
时,它没关系。但是当我运行/bin/sh
时,它会在shell退出之前输出。但我想读它的输出!
for(;;) {
select(PARENT_READ+1,&sh,NULL,NULL,NULL); // This unblocks only when shell exits!
if (FD_ISSET(PARENT_READ,&sh)) {
while (n = read (PARENT_READ, &buf,30)) {
buf[30]='\0';
printf("C: %s\n",buf);
};
};
}
答案是禁止缓冲管道的某个领域?
答案 0 :(得分:4)
许多程序根据他们是否认为他们正在与终端(tty)交谈来改变他们的行为,而shell肯定会这样做。此外,如果stdout
是tty,则默认C流stderr
和stdout
可能是无缓冲的,否则完全缓冲 - 这意味着它们在内部缓冲区已满之前不会刷新,程序显式刷新它们,或者程序结束。
要解决此问题,您必须使程序假装为终端。为此,您可以使用系统的伪终端API(尝试man 7 pty
)。最终结果是一对文件描述符,它们像管道一样工作。
另外,另外,当select select unblocks时,你应该从触发的文件描述符中读取一次。如果您多次阅读,这可能是您已经到达的循环,那么您可能会在后续读取时再次出现阻塞,除非您的FD处于非阻塞模式。
但是,我不得不问:为什么你需要以这种方式与shell进行交互?是否可以,比如运行shell脚本,或者使用“/ bin / sh -c your_command_here”代替?实际上需要真正的终端正常工作的程序相对较少 - 主要是提示输入密码的程序,如ssh
,su
或sudo
。