C 为什么不打印到标准输出(stdout)?
我目前正在创建自己的命令行shell,在尝试引入管道时遇到问题。我的程序从父进程开始。它检查用户是否输入exit或history。如果是这样,它会使用这些命令,但这并不重要。如果用户输入的不是退出或历史记录,那么它将创建一个执行当前任务的子任务 但是,如果用户输入一个具有单个管道的命令,那么我们从父进程开始,它创建一个子进程,称这个子进程为child 1。子1看到有一个管道,并使用fork创建另一个子,称这个子2。子1创建另一个子,称之为子3(注意:子2和子3使用共享内存)。现在,子2执行第一个命令,子3使用子2的输出执行命令。但由于某种原因,我没有得到任何输出 我不确定这是否是执行我任务的最有效方式,但这是我的教授说的 如果您想在此处查看我的所有代码,请访问: 否则,我的代码从子项1开始:C 为什么不打印到标准输出(stdout)?,c,debugging,process,pipe,pid,C,Debugging,Process,Pipe,Pid,我目前正在创建自己的命令行shell,在尝试引入管道时遇到问题。我的程序从父进程开始。它检查用户是否输入exit或history。如果是这样,它会使用这些命令,但这并不重要。如果用户输入的不是退出或历史记录,那么它将创建一个执行当前任务的子任务 但是,如果用户输入一个具有单个管道的命令,那么我们从父进程开始,它创建一个子进程,称这个子进程为child 1。子1看到有一个管道,并使用fork创建另一个子,称这个子2。子1创建另一个子,称之为子3(注意:子2和子3使用共享内存)。现在,子2执行第一个
//Otherwise if we have a single pipe, then do
else if (numPipes == 1) {
char *command1[CMD_MAX]; //string holding the first command
char *command2[CMD_MAX]; //string holding the second command
int fds[2]; //create file descriptors for the parent and child
pid_t new_pid; //create new pid_t obj
onePipeSplit(tokens, command1, command2, numTokens); //Getting each command for pipe
if (pipe(fds) < 0) { //use the pipe command. If < 0
perror("Pipe failure."); //we have an error, so exit
exit(EXIT_FAILURE);
}
//Creating child 2
new_pid = fork();
//if pid < 0 then we have an error. Exit.
if (new_pid < 0) {
perror("Fork failure.");
exit(EXIT_FAILURE);
}
//Else we have the child (2) process
else if (new_pid == 0) {
close(fds[0]); //Close read
//sending stdin to the shared file descriptor
if (dup2(fds[1], STDOUT_FILENO)<0) {
perror("Can't dup");
exit(EXIT_FAILURE);
}
execvp(command1[0], command1); //Execute the next command
perror("Exec failure");
exit(EXIT_FAILURE);
}
//Else if we have the parent process
else {
pid_t child = fork(); //Creating child 3
if (new_pid < 0) { //if pid < 0, error, exit
perror("Fork failure.");
exit(EXIT_FAILURE);
}
//else if pid > 0 we have the parent wait until children execute
else if (new_pid > 0) {
wait(NULL);
}
//else we have the child (3)
else {
close(fds[1]); //Close write
//Sending stdout to the shared file descriptor
if (dup2(fds[0], STDIN_FILENO) < 0) {
perror("Can't dup");
exit(EXIT_FAILURE);
}
execvp(command2[0], command2); //Execute the command
perror("Exec failure");
exit(EXIT_FAILURE);
}
}
}
//否则,如果我们只有一根管道,那么就这样做
else if(numPipes==1){
char*command1[CMD_MAX];//包含第一个命令的字符串
char*command2[CMD_MAX];//保存第二个命令的字符串
int fds[2];//为父级和子级创建文件描述符
pid\u t new\u pid;//创建新的pid\u t对象
onePipeSplit(令牌、command1、command2、numTokens);//获取管道的每个命令
if(pipe(fds)<0){//使用pipe命令。if<0
perror(“管道故障”);//我们有一个错误,所以退出
退出(退出失败);
}
//创建子2
new_pid=fork();
//如果pid<0,则出现错误。退出。
如果(新的pid<0){
perror(“Fork failure”);
退出(退出失败);
}
//否则我们就有了孩子(2)的过程
else if(新的_pid==0){
关闭(fds[0]);//关闭读取
//将stdin发送到共享文件描述符
如果(dup2(fds[1],STDOUT_FILENO)0,则让父级等待直到子级执行
否则如果(新pid>0){
等待(空);
}
//否则我们就有孩子了(3)
否则{
关闭(fds[1]);//关闭写入
//将标准输出发送到共享文件描述符
如果(dup2(fds[0],标准文件号)<0){
佩罗(“不能重复”);
退出(退出失败);
}
execvp(command2[0],command2);//执行命令
perror(“执行失败”);
退出(退出失败);
}
}
}
这是我的教授给我的一张图片,展示了它应该如何工作。
问题在于:
pid_t child = fork(); //Creating child 3
if (new_pid < 0) {
... you keep checking `new_pid` here on down,
... but you should be checking `child` here on down...
第二次之后:
command2[i] = NULL;
好的,还有一些修正:
在每次dup2()之后,需要关闭原始fd。例如:
if (dup2(fds[1], STDOUT_FILENO)<0) {
perror("Can't dup");
exit(EXIT_FAILURE);
}
close(fds[1]); /* ADD ME */
问题在于:
pid_t child = fork(); //Creating child 3
if (new_pid < 0) {
... you keep checking `new_pid` here on down,
... but you should be checking `child` here on down...
第二次之后:
command2[i] = NULL;
好的,还有一些修正:
在每次dup2()之后,需要关闭原始fd。例如:
if (dup2(fds[1], STDOUT_FILENO)<0) {
perror("Can't dup");
exit(EXIT_FAILURE);
}
close(fds[1]); /* ADD ME */
我认为你的孩子太多了。如果你有
foo | bar
,你需要一个管道和两个以上的进程(除了你的程序已经有的进程)。因此,parent创建了一个管道,p
parent分叉第一个孩子(这将是bar
)。child:close(p[1]);dup2(p[0],exec(“bar”);现在parent分叉第二次(这将是foo
)。子项:close(p[0]);dup2(p[1],1);exec(“foo”);
Parent:close(p[0]);close[p[1]);wait for children
@J.V.A.我在问题中添加了一个图像,显示了教授给我的内容。这是否意味着总共应该有3个孩子?不过我可能错了。我不确定shell(1)函数在做什么,但如果教授希望这样做,那么这就是正确的答案:)@j、 v.a好的,你明白为什么不打印到标准输出吗?我想你的孩子太多了。如果你有foo | bar
,你需要一个管道和两个以上的进程(除了你的程序已经是的那个)。所以家长创建一个管道,p
家长分叉第一个孩子(这将是bar
)。孩子:close(p[1]);dup2(p[0],0);exec(“bar”);
现在父级第二次分叉(这将是foo
)。子级:close(p[0]);dup2(p[1],1);exec(“foo”);
父级:close(p[0]);close[p[1]);wait for children
@J.V.A.我在问题中添加了一个图像,显示了教授给我的内容。这是否意味着总共应该有3个孩子?但我可能错了。我不确定是哪个函数shell(1)正在做,但如果教授希望这样做,那么这就是正确的答案:)@j.v.a好的,你知道为什么它没有打印到标准输出吗?谢谢你的回答。这修复了一个奇怪的错误,但不幸的是它仍然没有打印到标准输出。我会继续查找,但到目前为止我不确定问题是什么。你有第二个其他问题吗如果(new_pid>0){
,对吗?是的。我刚刚尝试摆脱第二个fork,所以现在shell(2)执行第一个命令并将管道传输到shell(1)它是有效的。这真的很奇怪,当我使用2个孩子时,它不起作用…我认为如果你的教授希望这样的话,你需要保留这3个过程。我完全同意,我只是想尝试一下,看看这个错误是否在其他地方。谢谢你的回答。这修复了一个奇怪的错误,但不幸的是它仍然存在