linux c实现简单shell

论坛 期权论坛 编程之家     
选择匿名的用户   2021-6-2 20:49   1778   0
/*简单的模拟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;
}


分享到 :
0 人收藏
您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

积分:3875789
帖子:775174
精华:0
期权论坛 期权论坛
发布
内容

下载期权论坛手机APP