为什么这不打印到标准输出 (stdout)?
Why is this not printing to standard output (stdout)?
我目前正在创建自己的命令行 shell,但在尝试接收管道时遇到了问题。我的程序从 parent 进程开始。它检查用户是否输入了退出或历史记录。如果是这样,它会使用那些命令,但这并不重要。如果用户输入除 exit 或 history 以外的任何内容,则会创建一个 child 来执行当前任务。
但是,如果用户输入的命令只有一个管道,那么我们从 parent 开始,它会创建一个 child 进程,调用这个 child,child 1. child 1 看到有一个管道并使用 fork 创建另一个 child,称之为 child 2. Child 1 创建另一个 child,称之为child3(注意:child2和3使用共享内存)。现在,child 2 执行第一个命令,child 3 使用 child 2 的输出执行命令。但由于某种原因我没有得到任何输出。
我不确定这是否是执行任务的最有效方式,但这是我的教授所说的。
如果您想在此处查看我的所有代码,它是:http://pastebin.com/YNTVf3XP
否则我的代码从 child 1:
开始
//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);
}
}
}
这是我的教授给我的一张图片,用于展示它应该如何工作。
问题出在这里:
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...
同样在 onePipeSplit
中,您需要在两个命令列表的末尾放置一个 NULL,因为 execvp
需要它。在第一个循环后添加:
command1[i] = NULL;
第二个之后:
command2[i] = NULL;
好的,还有一些修复:
在每个 dup2() 之后,您需要关闭原始 fd。一个例子:
if (dup2(fds[1], STDOUT_FILENO)<0) {
perror("Can't dup");
exit(EXIT_FAILURE);
}
close(fds[1]); /* ADD ME */
并且在父进程中:
//else if pid > 0 we have the parent wait until children execute
else if (child > 0) {
close(fds[0]); /* we don't use */
close(fds[1]); /* the pipe */
wait(NULL);
exit(0); /* when 2 & 3 are done, we are too */
}
我目前正在创建自己的命令行 shell,但在尝试接收管道时遇到了问题。我的程序从 parent 进程开始。它检查用户是否输入了退出或历史记录。如果是这样,它会使用那些命令,但这并不重要。如果用户输入除 exit 或 history 以外的任何内容,则会创建一个 child 来执行当前任务。
但是,如果用户输入的命令只有一个管道,那么我们从 parent 开始,它会创建一个 child 进程,调用这个 child,child 1. child 1 看到有一个管道并使用 fork 创建另一个 child,称之为 child 2. Child 1 创建另一个 child,称之为child3(注意:child2和3使用共享内存)。现在,child 2 执行第一个命令,child 3 使用 child 2 的输出执行命令。但由于某种原因我没有得到任何输出。
我不确定这是否是执行任务的最有效方式,但这是我的教授所说的。
如果您想在此处查看我的所有代码,它是:http://pastebin.com/YNTVf3XP
否则我的代码从 child 1:
开始 //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);
}
}
}
这是我的教授给我的一张图片,用于展示它应该如何工作。
问题出在这里:
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...
同样在 onePipeSplit
中,您需要在两个命令列表的末尾放置一个 NULL,因为 execvp
需要它。在第一个循环后添加:
command1[i] = NULL;
第二个之后:
command2[i] = NULL;
好的,还有一些修复:
在每个 dup2() 之后,您需要关闭原始 fd。一个例子:
if (dup2(fds[1], STDOUT_FILENO)<0) {
perror("Can't dup");
exit(EXIT_FAILURE);
}
close(fds[1]); /* ADD ME */
并且在父进程中:
//else if pid > 0 we have the parent wait until children execute
else if (child > 0) {
close(fds[0]); /* we don't use */
close(fds[1]); /* the pipe */
wait(NULL);
exit(0); /* when 2 & 3 are done, we are too */
}