【发布时间】:2017-04-02 16:04:51
【问题描述】:
我一直在用 C 语言制作一个迷你 shell,它必须接收带有至少 3 个参数的命令,解析它们,然后应用 fork() 和 exec(),如果你只是按 Enter,它应该会再次打印提示.它还必须接受多个管道,这就是我被卡住的地方。这是我的代码
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <sys/types.h>
#include <unistd.h>
#include <sys/wait.h>
int main(){
char command[50];
char* token;
char* param[50][50];
int i,j,k;
while(1){
printf("shell:~");
fgets(command, sizeof(command), stdin);
i=0,j=0;
token = strtok(command," \n\0\t");
while(1){
if(token==NULL) break;
else if(strcmp(token,"|")==0){
param[i][j]=0;
i = i+1;
j=0;
token = strtok(NULL," \n\0\t");
}
else{
param[i][j]=token;
token = strtok(NULL," \n\0\t");
j = j+1;
}
}
param[i][j]=0;
到目前为止一切正常。
pid_t pid1,pid2;
int fd1[2],fd2[2];
//int numpipe = i-1;
pipe(fd1);
pipe(fd2);
int status;
pid1 = fork();
if(pid1==0){
k=0;
while(k<i+1){
pid2 = fork();
if(pid2==0){
if(k==0){// if it is first
if(k==i){//and last one
execvp(param[k][0],param[k]);
}else{
dup2(fd1[1],STDOUT_FILENO);
close(fd1[0]);
execvp(param[k][0],param[k]);
}
}else if(0<k<i){//if it is in the middle
if(k%2==0){ // position odd
dup2(fd2[0],STDIN_FILENO);
close(fd2[1]);
dup2(fd1[1],STDOUT_FILENO);
close(fd1[0]);
execvp(param[k][0],param[k]);
}else{ //position
dup2(fd1[0],STDIN_FILENO);
close(fd1[1]);
dup2(fd2[1],STDOUT_FILENO);
close(fd2[0]);
execvp(param[k][0],param[k]);
}
}else{//if it is lasts
if(k%2==0){
dup2(fd2[0],STDIN_FILENO);
close(fd2[1]);
execvp(param[k][0],param[k]);
}else{
dup2(fd1[1],STDIN_FILENO);
close(fd1[1]);
execvp(param[k][0],param[k]);
}
}
}else{
k++;
wait(NULL);
}
}
}
else{
wait(NULL);
}
}
return 0;
}
如果我只使用 1 个命令,代码效果很好,但是当我放一个管道时它没有得到输入,例如:
shell:~ls -l
total 112
-rw-r--r-- 1 cristian cristian 72018 mar 28 13:25 (107315)proyecto1-SO2017-1.pdf
-rw-rw-r-- 1 cristian cristian 0 abr 2 12:23 a.out
-rw-rw-r-- 1 cristian cristian 1082 abr 1 23:47 reaspaldo2
-rw-rw-r-- 1 cristian cristian 1217 abr 2 03:00 reaspaldo2.c
-rw-rw-r-- 1 cristian cristian 962 abr 1 19:40 respaldo1
-rw-rw-r-- 1 cristian cristian 636 abr 2 01:10 respaldo1.c
-rwxrwxr-x 1 cristian cristian 13200 abr 2 12:35 shell
-rw-r--r-- 1 cristian cristian 1984 abr 2 12:36 shell.c
-rw-r--r-- 1 cristian cristian 807 mar 29 11:41 shell.c~
shell:~ls -l | wc
wc: 'standard input': Bad file descriptor
0 0 0
shell:~
它与 STDIN_FILE 相关,但我确信我没有很好地实现管道和分叉。
【问题讨论】:
-
您没有关闭所有文件描述符。通常,您的代码应类似于
pipe(fd); if(fork()==0) {close(fd[0]); dup2(fd[1],STDOUT_FILENO); close(fd[1]) -
是的,我也试过了,但是效果一样,就像 excvp() 没有从管道中获取参数
-
一次解决一个问题。您根本没有关闭父级中的任何文件描述符!但更直接的问题是
dup2(fd1[1],STDIN_FILENO);。fd[1]是管道的写入端,应该写入。尝试从中读取将产生您所看到的错误。