【Linux】项目-minishell的实现

minishell的实现

实现原理

  我们在这里手动实现一个小型的shell,可以用来处理我们一般常规的指令如ls,还可以附加参数-l,并且还可以进行重定向操作。
  实现原理很简单,我们将用户输入的字符串读取到我们的缓冲区中,然后首先遍历一遍整个缓冲区看是否存在重定向符>或者>>,并且将重定向符改为\0并且读取出重定向的文件,随后保存判断结果。之后我们再次遍历一遍进行指令处理,我们利用字符指针数组让每一个指针指向每一个指令,并且将之间的空白符如(空格)改为\0。做完以上这一切,创建子进程利用进程替换将其替换为目标指令中的程序让其执行指定功能,如果有重定向符要先打开指定文件并且将标准输入重定向到指定文件中,者必须在子进程中完成,然后等待子进程关闭,父进程阻塞,并且让以上过程不断循环即可。

代码实现

/*minishell实现*/                                          

#include <stdio.h>
#include <unistd.h>    
#include <stdlib.h>
#include <fcntl.h>                
#include <string.h>
#include <ctype.h>       
#include <sys/wait.h>
char buf[1024] = {0};
char* argv[32];      
int argc = 0;                                              
                                              
//指令输入到缓冲区中
void do_face()      
{                             
  printf("[san@localhost]$ ");
  fflush(stdout);             
  memset(buf, 0x00, 1024);                                 
  //%[^\n]    获取数据直到遇到\n              
  //%*c 取出一个字符丢弃        
  //利用正则表达式,取出指令输入字符串
  if (scanf("%[^\n]%*c", buf) != 1)      
  {                             
    //如果没有输入指令我们需要处理回车,将回车从缓冲区取出
    getchar();                                            
  }           
  return ;     
}
//处理指令,将字符指针数组每个指针指向每个指令
void do_parse()
{                                                         
  char *ptr = buf;
  argc = 0;
  while(*ptr != '\0') 
  {
    //当前位置非空白字符
    if (!isspace(*ptr)) 
    {
      argv[argc++] = ptr;
      while(!isspace(*ptr) && *ptr != '\0')
      {
        ptr++;
      }
    }
    //所有空字符都换为'\0'
    else 
    {
      *ptr = '\0';
      ptr++;
    }
    }
  }
  argv[argc] = NULL;
  return;
}
int main()
{
  // ls >>  >   a.txt
  // int fd = open(a.txt);
  // dup2(fd, 1);
  // 将原先要写入到标准输出1中的数据,写入到指定文件中
  while(1) 
  {
    do_face();
    //ls  >> a.txt
    //解析命令中是否有重定向指令                            
    //没有则跳过此步骤
    int redirect = 0;
    char *file = NULL;
    char *ptr = buf;
    while(*ptr != '\0') 
    {
      if (*ptr == '>')
      {
        redirect = 1;//清空重定向
        *ptr++ = '\0';
        if (*ptr == '>') 
        {
          redirect = 2;//追加重定向
          *ptr++ = '\0';
        }
        //isspace如果是空字符(制表符回车空格等则返回1)
        //循环跳过中间所有空字符
        while(isspace(*ptr) && *ptr != '\0') 
        {
          ptr++; 
        }
        file = ptr;
        //拿到要写入的文件名存入file
        while(!isspace(*ptr) && *ptr != '\0') 
        {
          ptr++; 
        }                                                       
        *ptr = '\0';
      }
      ptr++;
    }
    //解析流程:取出空白字符,获取程序名称和参数
    do_parse();
    //创建子进程
    int pid = fork();                                              
    if (pid < 0) 
    {
      exit(-1);
    }
    else if (pid == 0) 
    {
      //重定向必须在子进程当中完成
      //重定向处理
      if (redirect == 1) 
      {

        //清空重定向
        int fd = open(file, O_CREAT|O_WRONLY|O_TRUNC, 0664);
        //将标准输出重定向到file所指向的文件中
        dup2(fd, 1);
      }
      else if (redirect == 2) 
      {
        //追加重定向
        int fd = open(file, O_CREAT|O_WRONLY|O_APPEND, 0664);
        //将标准输出重定向到file所指向的文件中
        dup2(fd, 1);
      }
      //将子进程替换为指令中要求的程序,执行相应的指令
      execvp(argv[0], argv);
      //防止子进程替换失败
      exit(0);
    }
    wait(NULL);
  }
  return 0;
}                                               
  • 1
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值