【发布时间】:2016-02-26 08:11:32
【问题描述】:
我必须编写一个可以运行管道的 shell。例如像ls -l | wc -l"这样的命令。我已经成功解析了用户给出的命令如下:
"ls" = firstcmd
"-l" = frsarg
"wc" = scmd
"-l" = secarg
现在我必须使用两个叉子,因为命令是两个和一个管道。 我为执行命令而编写的代码块如下:
pid_t pid;
int fd[2];
pipe(fd);
pid = fork();
if(pid==0)
{
dup2(fd[WRITE_END], STDOUT_FILENO);
close(fd[READ_END]);
execlp(firstcmd, firstcmd, frsarg, (char*) NULL);
}
else
{
pid=fork();
if(pid==0)
{
dup2(fd[READ_END], STDIN_FILENO);
close(fd[WRITE_END]);
execlp(scmd, scmd, secarg, (char*) NULL);
}
}
因此,当我运行我的 shell 并输入命令 ls -l | wc -l(例如)时,execs 的结果不会显示,但 shell 会继续正常运行。
奇怪的是,命令的结果只有在我用“exit”或“^C”终止我的shell时才会显示。
该输出有什么问题?为什么我输入命令后没有立即显示?
【问题讨论】:
-
需要关闭父进程中的管道FD。
-
您能否编辑我的代码以帮助我理解您的意思? @Barmar
-
经验法则:如果将管道的一端复制到标准输入或标准输出,则应在使用
exec*()函数之前关闭原始管道的两端(或以其他方式继续)。有例外;他们少之又少。很少(在 SO 和 IRL 上)您会遇到使用关闭太多描述符的管道的程序;找到一个没有关闭足够描述符的程序是很常见的。如果有多个孩子和/或多个管道来混淆事物,这种情况尤其常见。 -
顺便说一下,如果您查看github.com/jleffler/soq/tree/master/src/so-4380-8114 中的代码,您会发现一个有趣的示例,其中“没有关闭足够多的文件描述符导致程序在足够大的输入上失败”。当输入很小时,它工作得很好。当输入足够大时,由于管道没有正确关闭,程序就会陷入僵局。 (不,干扰代码并不直接在 Stack Overflow 上。)