在我的操作系统签名中使用c制作UNIX minishell。我只需要改进shell本身,我们有一个预制的解析器用于实现yacc,扫描器用于实现lex和其他文件。 要修改的文件是msh.c,即主要的可执行文件。
好吧,当我尝试实现管道安全时,问题就开始了。这就是我所做的:
int executePipeLine (char*** argvv, int bg, char** filev, int n){
int i;
int in = 0;
pid_t pid;
int fd[2];
for (i = 0 ; i < n-1 ; i++){
pipe(fd);
pid_t pid = fork();
if (pid == 0){ //child
if (in != STDIN_FILENO){
dup2(in, STDIN_FILENO);
close(in);
}
if (fd[1] != STDOUT_FILENO){
dup2(fd[1], STDOUT_FILENO);
close(fd[1]);
}
execvp(argvv[i][0], argvv[0]);
}
else { //parent
close(fd[1]);
in = fd[0];
}
}
if(in != STDIN_FILENO){
dup2(in, STDIN_FILENO);
close(in);
}
pid_t lastpid = fork();
if(lastpid == 0){ //child
execvp(argvv[i][0], argvv[0]);
}
if(lastpid == -1){
perror("no se pudo crear el hijo\n");
exit(-1);
}
else { //parent
/* not bg*/
if(!bg ) {
int status;
while (wait(&status) != lastpid); /* wait the child. */
}
else {
/*bg mode*/
printf("pid del proceso last: %d\n", lastpid);
}
return 0;
}
}//end executePipeLine
这似乎工作正常。在main中,我们有一个名为obtain_order()的extern函数;返回命令数+ 1并将其保存到ret。如果ret为1,我们继续提示,如果0表示EOF(Control + D键绑定)结束shell,如果是> 1则执行命令。
在这里你拥有它:
int main(void)
{
char ***argvv;
int command_counter;
int num_commands;
int args_counter;
char *filev[3];
int bg;
int ret;
int reset = 0;
setbuf(stdout, NULL); /* Unbuffered */
setbuf(stdin, NULL);
while (1)
{
fprintf(stderr, "%s", "msh> "); /* Prompt */
ret = obtain_order(&argvv, filev, &bg);
printf("ret: %d\n", ret);
if (ret == 0) break; /* EOF */
if (ret == -1) continue; /* Syntax error */
num_commands = ret - 1; /* Line */
if (num_commands == 0) continue; /* Empty line */
if(num_commands > 1){
executePipeLine(argvv, bg, filev, num_commands);
}
else if (num_commands == 1){
executeCommand(argvv, bg, filev);
}
} //fin while
return 0;
} //end main
只需简单的命令即可正常工作。问题是当我尝试执行管道时。它显示了一个很好的结果,但我不知道我们,之后ret在下一次迭代中总是0,所以每次我尝试执行一个管道时,它都可以工作但是关闭shell进程,并且必须再次执行它而不是继续承诺。
你知道这里有什么问题吗?
我希望你理解我,我的英语不是完美的。感谢
答案 0 :(得分:0)
在父进程(即你的迷你shell)中,你是dup
标准输入:
...
else { //parent
close(fd[1]);
in = fd[0];
}
...
if(in != STDIN_FILENO){
dup2(in, STDIN_FILENO);
close(in);
}
当您的管道终止时,孩子们已经死了,管道不再可读=&gt; stdin被认为是封闭的。当您稍后在主循环中调用obtain_order
时,它将返回0(EOF)并退出程序。