现在的位置: 首页 > 综合 > 正文

linux c实现简单shell

2013年09月19日 ⁄ 综合 ⁄ 共 2770字 ⁄ 字号 评论关闭
/*简单的模拟shell,可以执行带一个输入重定向(或输出重定向或管道)命令,程序存在不完善之处,基本能用*/
#include<stdio.h>
#include<stdlib.h>
#include<ctype.h>
#include<string.h>
#include<unistd.h>
#include<fcntl.h>
#include<sys/types.h>
#include<sys/wait.h>
#include<dirent.h>

char command[100]; /*存放命令*/
char argv[50][50]; /*存放分解后的命令*/
int count;         /*命令分解后的个数*/
/*枚举类型,依次表示一般命令,带输出重定向命令,带输入重定向命令,带管道命令*/
enum specify{NORMAL,OUT_REDIRECT,IN_REDIRECT,PIPE};

/*函数声明*/
int analysis_command();
int do_command();
int find_command(char *command);

/*主函数*/
int main()
{
    while(1){
        printf("$my_shell:");
	command[0]=0;
        gets(command);
        if(!analysis_command())
	   continue; 
	do_command();
    }
    return 0;
}

/*解析命令*/
int analysis_command()
{
    char *s=command;
    int i=0,j=0,state=0;
    strcat(command," ");
    /*按空格为分隔符将命令分隔开来,存放在argv中*/
    while(*s){
	switch(state){
           case 0:
	       if(!isspace(*s))
		   state=1;
	       else
		   s++;
	       break;
	   case 1:
	       if(isspace(*s)){
		   argv[i][j]='\0';
		   i++;
		   j=0;
		   state=0;
	       }else{
		   argv[i][j]=*s;
		   j++;
	       }
	       s++;
	       break;
	}
    }
    count=i;
    if(count==0)
	return 0;

    if(strcmp(argv[0],"logout")==0 || strcmp(argv[0],"exit")==0)
	exit(0);


    /*判断命令是否存在*/
    if(!find_command(argv[0])){
	puts("error:can't find command");
	return 0;
    }
    return 1;   
}

/*执行命令*/
int do_command()
{
    int i,j;
    char* file;
    char* arg[50];
    char* arg2[50];
    int f=0,back_run=0;
    int fd,pid,fd2,pid2;
    enum specify type=NORMAL;

    for(i=0;i<count;i++){
	arg[i]=argv[i];
    }
    arg[i]=NULL;

    if(strcmp(arg[count-1],"<")==0 || strcmp(arg[count-1],">")==0 || strcmp(arg[count-1],"|")==0){
	printf("error:command error\n");
	return 0;
    }
    	
    for(i=0;i<count;i++){
	if(strcmp(arg[i],"<")==0){
            f++;
	    file=arg[i+1];
	    arg[i]=NULL;
	    type=IN_REDIRECT;
	}else if(strcmp(arg[i],">")==0){
	    f++;
	    file=arg[i+1];
	    arg[i]=NULL;
	    type=OUT_REDIRECT;
	}else if(strcmp(arg[i],"|")==0){
	    f++;
	    type=PIPE;
	    arg[i]=NULL;
	    for(j=i+1;j<count;j++){
		arg2[j-i-1]=arg[j];
	    }
	    arg2[j-i-1]=NULL;
	    if(!find_command(arg2[0])){
		printf("error:can't find command\n");
		return 0;
	    }
	}
    }

    if(strcmp(arg[count-1],"&")==0){
	back_run=1;
	arg[count-1]=NULL;
    }

    if(f>1){
	printf("error:don't identify the command");
	return 0;
    }

    pid=fork();
    if(pid<0){
	perror("fork error");
        exit(0);
    }else if(pid==0){/*在子进程里*/
        switch(type){
            case NORMAL:
		execvp(arg[0],arg);
	        break;
	    case IN_REDIRECT:
		fd=open(file,O_RDONLY);
		dup2(fd,STDIN_FILENO);
                execvp(arg[0],arg);
		break;
	    case OUT_REDIRECT:
		fd=open(file,O_WRONLY|O_CREAT|O_TRUNC,0666);
		dup2(fd,STDOUT_FILENO);
		execvp(arg[0],arg);
		break;
	    case PIPE:
		pid2=fork();
		if(pid2==0){
		    fd2=open("tempfile",O_WRONLY|O_CREAT|O_TRUNC,0600);
		    dup2(fd2,STDOUT_FILENO);
		    execvp(arg[0],arg);
		}else{
		    waitpid(pid2,NULL,0);
		    fd=open("tempfile",O_RDONLY);
		    dup2(fd,STDIN_FILENO);
		    execvp(arg2[0],arg2);
		}
		break;
        }
    }else{
       if(!back_run)
           waitpid(pid,NULL,0);
    }
    return 1;
}



/*查找命令*/
int find_command(char *command)
{
    DIR *d;
    struct dirent *ptr;
    char temp[100];
    char *dir;
    /*获得环境变量*/
    char *path=getenv("PATH");
    /*分隔环境变量,且依次查找各个目录看命令是否存在*/
    strcpy(temp,path);
    dir=strtok(temp,":");
    while(dir){
        d=opendir(dir);
        while((ptr=readdir(d)) != NULL)
	    if(strcmp(ptr->d_name,command) == 0){
		closedir(d);
		return 1;
	    }
	closedir(d);
	dir=strtok(NULL,":");
    }
    return 0;
}

抱歉!评论已关闭.