我想创建一个基于UNIX的shell
,它支持带有1个管道的命令。
例如,命令ls | wc
我已经写了下面的代码但是当我尝试像上面这样的输入时,程序很奇怪并且无法弄清楚故障的位置。
更具体地说,fork()
正确显示,然后exec()
显示正确的参数,但只有管道(ls)之前的命令正确退出。管道(wc)之后的命令实际上从不退出,因此程序没有输出。
我已经放了一些printf
来帮助我弄清楚代码中的错误在哪里。
功能fetch_input
和string_tokenizer
已经过测试并且运行正常。
故障必须位于代码中指向的点之下。 任何帮助我找出错误的建议都将受到赞赏。
提前致谢。
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <unistd.h>
#define ANSI_COLOR_GREEN "\x1b[32m"
#define ANSI_COLOR_CYAN "\x1b[36m"
#define ANSI_COLOR_RESET "\x1b[0m"
char * fetch_input(char * buffer);
char * trim(char * string);
char ** string_tokenizer(char * string, char c);
int main(int arc, char * argv[]){
char *input, *init_input, **commands, **com1, **com2;
pid_t fork_pid_1, fork_pid_2, ret_pid;
int stat,i, fd[2];
init_input = (char *)malloc(sizeof(char)*256);
input = init_input;
input = fetch_input(input);
while(strcmp(input,"exit")!=0){
commands = string_tokenizer(input,'|');
com1 = string_tokenizer(commands[0],' ');
if(commands[1]==0){
fork_pid_1 = fork();
if(fork_pid_1<0){
printf("Fork Error!\n");
_exit(1);
}
else if(fork_pid_1==0){
execvp(com1[0],com1);
printf("Exec Error!\n");
_exit(1);
}
else{
ret_pid=wait(&stat);
}
}
else{ //the fault is probably somewhere below that point
if(pipe(fd)<0){ _exit(1);}
fork_pid_1 = fork();
if(fork_pid_1<0){
printf("Fork Error!\n");
_exit(1);
}
else if(fork_pid_1==0){
printf("First command, ready to exec...(pid:%d)\n",getpid());
close(fd[0]);
dup2(fd[1],1);
close(fd[1]);
execvp(com1[0],com1);
printf("Exec Error!\n");
_exit(1);
}
else{
com2 = string_tokenizer(commands[1],' ');
fork_pid_2=fork();
if(fork_pid_2<0){
printf("Fork Error!\n");
_exit(1);
}
else if(fork_pid_2==0){
printf("Second command, ready to exec...(pid:%d)\n",getpid());
close(fd[1]);
dup2(fd[0],0);
close(fd[0]);
execvp(com2[0],com2);
printf("Exec Error!\n");
_exit(1);
}
else{
printf("Now we 're in the parent process...(p_pid:%d)\n",getpid());
while( (ret_pid=waitpid(-1,&stat,0)) >0 ){
printf("Child process (%d) exited with status:%d\n",ret_pid,stat);
}
}
}
}
input = init_input;
input = fetch_input(input);
}
return 0;
}
char * fetch_input(char * buffer){
int i, sum;
do{
printf(ANSI_COLOR_CYAN "$" ANSI_COLOR_RESET);
fflush(stdin);
fgets(buffer,256,stdin);
if(buffer[strlen(buffer)-1]=='\n'){
buffer[strlen(buffer)-1]='\0';
}
sum=0;
for(i=0;i<strlen(buffer);i++){
if(buffer[i]==' '){sum++;}
}
}while(strlen(buffer)==sum);
buffer = trim(buffer);
return buffer;
}
char * trim(char * string){
int i;
i=strlen(string);
while(string[i-1]==' '){
i--;
}
*(string+i)='\0';
while(isspace(*string)){string++;}
return string;
}
char ** string_tokenizer(char * string, char c){
int j=0,k,i,done,found,first,last;
char ** ret, *str;
str=string;
if( (str==0) || (strlen(str)==0) ) return NULL;
ret = (char **)malloc(sizeof(char*));
do{
done=0;
found=0;
i=0;
first=-1;
last=-1;
while( (str[i]!='\0') && (done==0) ){
if( (str[i]==c) && (found==0) ){
i++;
}
else if( (str[i]!=c) && (found==0) ){
found=1;
first=i;
i++;
}
else if( (str[i]!=c) && (found!=0) ){
i++;
}
else if( (str[i]==c) && (found!=0) ){
done=1;
last=i;
}
}
if(done!=0){
*(ret+j) = (char *)malloc(sizeof(char)*(last-first+1));
for(k=first;k<last;k++){
*(*(ret+j)+(k-first)) = str[k];
}
*(*(ret+j)+(k-first)) = '\0';
*(ret+j) = trim(*(ret+j));
j++;
str=str+last;
}
}while(done!=0);
if( (done==0) && (found==0) ){
*(ret+j)=NULL;
}
else if( (done==0) && (found!=0) ){
*(ret+j) = (char *)malloc(sizeof(char)*(i-first+1));
for(k=first;k<i;k++){
*(*(ret+j)+(k-first)) = str[k];
}
*(*(ret+j)+(k-first)) = '\0';
*(ret+j)=trim(*(ret+j));
*(ret+j+1) = NULL;
}
return ret;
}