自己写的shell程序 多层管道、重定向、后台、命令历史

#include<stdio.h>
#include<stdlib.h>
#include<unistd.h>
#include<fcntl.h>
#include<string.h>
#include<stdbool.h>
#include<signal.h>
#include <readline/readline.h>
#include <readline/history.h>
//#include<errno.h>
//#include<sys/stat.h>

#define MAX_LINE_SIZE 100
#define MAX_ARGC 20 //最多20个参数
#define MAX_ARGLEN 50  //每个参数最大长度
#define MAX_FILE_NAME 100
#define FIFO "/tmp/my_fifo"

FILE *his;
char *temp,*temp1,*fileName;
static char *line_read = (char *)NULL;
char* nextcmd;
char *argv[MAX_ARGC];
unsigned char argc=0;
bool is_pipe;
char buf[1000];
bool is_bg;
bool fromsigc = false;

void sig_child(int n){}

void sig_C(int n)
{
 printf("\n[COMMAND_LINE_$] ");
 fflush(stdout); 
 fromsigc = true;
 return;
}

//提取参数
void divArgs(char* argv[],char* cmd)
{
 int argc=0;
 while((argv[argc] = (char*)malloc(sizeof(char)*MAX_ARGLEN)) &&
    EOF!=sscanf(cmd,"%s",argv[argc]) && argc<=MAX_ARGC)
  {
   while(isspace(cmd[0])) cmd++;
   cmd+=strlen(argv[argc++]);
  }
  argv[argc] = NULL;
  
}
//输入命令

char *rl_gets()
{
 if(line_read)
 {      
  free (line_read);
  line_read = (char *)NULL;
 }
 if(fromsigc)
  line_read = readline(NULL);
 else
  line_read = readline("[COMMAND_LINE_$] ");
 fromsigc = false;

 if(line_read && *line_read)
  add_history(line_read);
 return(line_read);
}

void trim_tail(char* str)
{
 int i=strlen(str)-1;
 for(;isspace(str[i]);str[i--]='\0');
}

char* trim(char* str)
{
 while(isspace(*str))
  str++;
 trim_tail(str);
 return str;
}

bool isbg(char* str)
{
 bool flag = false;
 int i=strlen(str)-1;
 for(;isspace(str[i]) || str[i]=='&';str[i--]='\0')
  if(str[i]=='&')
   flag = true;
 return flag;
}

void div_and_deal(char* str,char* delim,void (*fn)(void*))
{
 char *token=0;
 for(token=strtok(str,delim);token!=NULL;token=strtok(NULL,delim))
 {
  (*fn)(token);
 }
}

bool deal_redirect(char* cmd, int *rd, int *in, int *out)
{
 char *p;
 int i=0;
 //  rd: null:0    <:1     >>2     >3
 while((p=strchr(cmd,'<')) || (p=strchr(cmd,'>'))){
  i = 0;
  *rd = 3;
  if(p[0]=='<')
   *rd = 1;
  *p++ = ' ';
  if((*rd !=1) && (p[0]=='>')){
   *rd = 2;
   *p++ = ' ';
  }
  while(isspace(*p)) p++;
  if(!p)
   return false;
  char fp[MAX_FILE_NAME];
  while(p && *p!='\0' && *p!='>' && *p!='<' && !isspace(*p)){
   fp[i++] = *p;
   *p++ = ' ';
  }
  fp[i]='\0';
  if(*rd == 1)
   *in = open(fp,O_RDONLY);
  else if(*rd == 2)
   *out = open(fp,O_WRONLY | O_CREAT | O_APPEND,0664);
  else
   *out = open(fp,O_WRONLY | O_CREAT | O_TRUNC,0664);
 }
}

void execute(char* cmd,int in, int out)
{
 pid_t pid,pid1,pid2;
 char *cmd1,*cmd2,*p;
 int fd;
 int status;
 int rd = 0;

 if(p=strchr(cmd,'|'))
 {
  cmd1=cmd;
  cmd2=p+1;
  *p='\0';

  deal_redirect(cmd1, &rd, &in, &out);

  divArgs(argv,cmd1);
  unlink(FIFO);
  mkfifo(FIFO, 0666);
     
  if((pid1=fork())==0){
   fd=open(FIFO,O_WRONLY);
   dup2(fd,STDOUT_FILENO);
   dup2(in,STDIN_FILENO);
   dup2(out,STDOUT_FILENO);
   if(execvp(argv[0],argv)<0){
    printf("cmd error!\n");
    close(fd);
   }
  }else{
   if((pid1=fork())==0){
    fd = open(FIFO, O_RDONLY);
    if(rd != 2 && rd != 3)
     in = fd;
    execute(cmd2,in,STDOUT_FILENO);
    close(fd);
    exit(0);
   }else{
    if(!is_bg){
     waitpid(pid1,&status,0);
     waitpid(pid2,&status,0);
    }
   }
  }

 }else{
  deal_redirect(cmd, &rd, &in, &out);
  divArgs(argv,cmd);
  if((pid=fork())==0){
   dup2(in,STDIN_FILENO);
   dup2(out,STDOUT_FILENO);
   if(execvp(argv[0],argv)<0){
    printf("error\n");
    exit(-1);
   }
  }else{
   if(!is_bg)
    waitpid(pid,&status,0);
  }
 }
 if(in != STDIN_FILENO) close(in);
 if(out != STDOUT_FILENO) close(out);
 for(argc;argc>0;free(argv[argc]))argc--;
 
}

void execmd(char* cmd)
{
 //bg
 is_bg = isbg(cmd);
 char* command = strdup(cmd);
 execute(command,STDIN_FILENO,STDOUT_FILENO);
}

int main()
{
 signal(SIGINT,sig_C);
 signal(SIGCHLD,sig_child);
 printf("*************shell*************\n");
 while(true)
 {
  char * line_=trim(rl_gets());
  //退出
  if(!strcmp(line_,"exit"))
  {
   break; 
  }
  //没有输入
  if(line_[0]=='\0')
  {
   continue;
  }
  temp1=temp = strdup(line_);
  //执行
  div_and_deal(temp,";",(void (*)(void*))execmd);
  free(temp1);
 }
 return 0;
}

readline 库的使用方法:http://www.cnblogs.com/pswzone/archive/2012/04/14/2446796.html

原文地址:https://www.cnblogs.com/pswzone/p/2447409.html