我一直在制作执行管道的简单外壳。
这是一些用于操作管道语法的代码。
int fd[2];
int stdin_copy;
int stdout_copy;
int status;
char * msg;
if (pipe(fd) == -1) {
perror("pipe");
exit(1);
}
// fd[0] : process read from fd[0]
// fd[1] : process write to fd[1]
if (execok(pr_words) == 0) { /* is it executable? */
status = fork(); /* yes; create a new process */
if (status == -1) { /* verify fork succeeded */
perror("fork");
exit(1);
} else if (status == 0) { /* in the child process... */
stdout_copy = dup(1);
close(1); // close standard output
dup(fd[1]);
close(fd[0]);
close(fd[1]); // close and fd[1] will be stdout
pr_words[l_nwds] = NULL; /* mark end of argument array */
status = execve(path, pr_words, environ); /* try to execute it */
perror("execve"); /* we only get here if */
exit(0); /* execve failed... */
}
/*------------------------------------------------*/
/* The parent process (the shell) continues here. */
/*------------------------------------------------*/
else if (status > 0) { // in the parent process....
wait( & status); /* wait for process to end */
if (execok(af_words) == 0) {
if (pipe(fd2) == -1) {
perror("pipe");
exit(1);
}
status = fork();
if (status == -1) {
perror("fork");
exit(1);
} else if (status == 0) { // in the child process...
stdin_copy = dup(0);
close(0);
dup(fd[0]);
close(fd[1]);
close(fd[0]);
read(fd[0], readbuffer, sizeof(readbuffer));
af_words[r_nwds] = NULL; /* mark end of argument array */
status = execve(path, af_words, environ); /* try to execute it */
} else if (status > 0) {
wait( & status);
msg = "over";
write(2, msg, strlen(msg));
close(fd[0]);
close(fd[1]);
dup2(stdin_copy, 0);
dup2(stdout_copy, 1);
close(stdin_copy);
close(stdout_copy);
printf("%s", "hi");
}
} else {
/*----------------------------------------------------------*/
/* Command cannot be executed. Display appropriate message. */
/*----------------------------------------------------------*/
msg = "*** ERROR: '";
write(2, msg, strlen(msg));
write(2, af_words[0], strlen(af_words[0]));
msg = "' cannot be executed.\n";
write(2, msg, strlen(msg));
}
}
} else {
/*----------------------------------------------------------*/
/* Command cannot be executed. Display appropriate message. */
/*----------------------------------------------------------*/
msg = "*** ERROR: '";
write(2, msg, strlen(msg));
write(2, pr_words[0], strlen(pr_words[0]));
msg = "' cannot be executed.\n";
write(2, msg, strlen(msg));
}
pr_words 和 af_words 是包含命令、管道右侧和左侧的二维指针。(例如 ls | cat -> pr_words = "ls\0" ,af_words = "cat\0")
而且,首先我使用 fork() 创建子进程并将 fd[1] 注册为标准输出。(并在关闭标准输入之前保存标准输入文件描述符)并在执行命令左侧之后,使其他子进程用于处理命令右侧。
同样,我在关闭标准输出之前保存了标准输出文件描述符并制作了 fd[0] 标准输入。通过使用 execve 函数的第一个结果的输入,我认为每个结果都将保存在 fd[1] 中。(因为这目前已注册为标准输出)。
最后,将管道输入和输出恢复为标准输出。(我不想使用 dup2 但由于我缺乏知识我别无选择)
但是,在执行此代码后,我输入了 'ls | cat',没有输出。此外,我设置终端的每个条目都将打印'#'。(这意味着'#ls'或'#cat'......)但是,在输入上述管道命令后,该程序甚至不打印'#'。
我猜这个程序的输入和输出流在处理完管道命令后完全扭曲了。
我该如何解决?我的意思是,我想将第一个 execve 的结果保存到 fd[1] 中,并在使用这个 fd[1] 执行第二个 execve 之后,将通过 stdout 文件描述打印最终结果。