模拟实现简易版shell(需要单独处理 ls+cd+export)

目录

[minishell -- 简易版shell](#minishell -- 简易版shell)

大致思路

注意点

ls

cd

export

代码


minishell -- 简易版shell

大致思路

  • 首先确定,我们的shell是一直在运行的(while(1))
  • 每次都会有提示信息打印出来 xxx@xxx x
  • 输入命令(+选项),其中,我们需要将读入的字符串分开,不然只是没有意义的字符串(然后作为参数传给exec命令)
  • 创建子进程执行命令(实际上还是调用系统中的可执行文件)

注意点

ls

ls在我们平常使用的命令行中,是默认添加一个选项的(可以将不同类型的文件用不同的颜色显示出文件名),所以我们记得要把它添加上

cd

  • 我们其他指令可以直接让子进程去执行
  • 但是!!cd是让shell本身改变当前工作目录的命令,让子进程改变的话将毫无意义
  • 因为我们的父进程才是shell !
  • 所以一旦执行cd命令,应该在父进程中执行
  • 但是不能使用exec系列函数,否则执行完cd后,我们写的shell就退出了(while循环被替换掉了
  • 所以直接使用系统调用接口来改变当前工作目录

export

  • 如果想要添加环境变量,需要将输入的环境变量手动添加到父进程自己的环境变量中
  • 并且,因为我们是使用指针数组存储分开的命令的
  • 如果直接将该字符串添加到**environ(也是一个指针数组)**中,也是无法保存下来的
  • 因为while每次循环都会将保存输入命令的那个字符串**格式化 --**也就是说,之前输入的环境变量内容也会被清空
  • 所以需要我们另外设置一个数组来存储该环境变量,并且保证它不能被清除,即可保存下来输入的环境变量
  • 但是,该如何存储呢?
  • 如果定位为全局变量,当我们再次定义一个环境变量,就会把前一个替代掉
  • 所以我们需要动态开辟空间,最后在shell退出时,才释放资源

代码

cpp 复制代码
#include<stdlib.h>
#include<stdio.h>
#include<unistd.h>
#include<sys/types.h>
#include<sys/wait.h>
#include<string.h>

#define num 1024
#define size 32
#define SEP " "

char cmd[num];
char* options[size];

int main(){
  extern char** environ; //将环境变量引入进来
  while(1){
    //打印前缀
    printf("root@localhost myshell#");
    fflush(stdout);
    //清空每次输入的命令
    memset(cmd,'\0',sizeof cmd);
    //读入命令
    if(fgets(cmd,sizeof cmd,stdin)==NULL){
      continue;
    }//ctrl+c to quit
    cmd[strlen(cmd)-1]='\0'; //去掉最后读入的\n
    //分割命令
    options[0]=strtok(cmd,SEP);
    int i=1;
      if(strcmp(options[0],"ls")==0){   //将ls单独处理
        options[i++]="--color=auto";
      }
    while(1){
      options[i++]=strtok(NULL,SEP);
      if(options[i-1]==NULL){
        break;
      }
    }
    //export需要提前处理,将环境变量单独存储,并且手动加入到父进程的环境变量中
    if(strcmp(options[0],"export")==0){
      char* my_env=(char*)malloc(sizeof(char)*sizeof(options[1])); 
      strcpy(my_env,options[1]);
      putenv(my_env);
      continue;
    }
   // for(i=0;options[i];i++){  //调试用
   //   printf("%s\n",options[i]);
   // }
    //cd需要在父进程进行
    if(strcmp(options[0],"cd")==0){
      if(options[1]!=NULL){
        chdir(options[1]);  //change work_path
      }
      continue;
    }
    //创建子进程
    pid_t id=fork();
    if(id==0){
      printf("im child\n");
      execvpe(options[0],options,environ);  //执行命令
      exit(1);
    }
    else{
      int status=0;
      pid_t ret=waitpid(-1,&status,0);
      if(ret>0){  //success
        printf("%s:%d\n",options[0],WEXITSTATUS(status));
      }
      else{   //fail
        printf("fail\n");
      }
    }
  }
  return 0;
}
相关推荐
忆挽篱笙歌1 小时前
通信连接,匿名管道
linux·服务器·网络
无足鸟ICT4 小时前
【RHCA+】安装Tuned
linux·服务器·centos
测试界的小码农9 小时前
【Linux 命令实战(06):Linux 文件权限管理,掌握 chmod、chown、chgrp】
linux·运维·服务器
艺杯羹10 小时前
1Panel 装好后 ufw 仍是 inactive:一次服务器安全盲区复盘
服务器·数据库·安全·网络安全·系统架构·实战·1panel
一条破秋裤10 小时前
【1114】【并发控制】【笔记】
linux
2035去旅行12 小时前
ADB的底层原理
linux·adb·嵌入式·arm·soc
武子康12 小时前
单卡 A6000 跑 Qwen-Drive:怎样留下可比较的第一条基线?
linux·人工智能·深度学习
女神下凡12 小时前
芯参谋(107):杰理AC_中科蓝讯_开发指南
linux·服务器·网络·单片机·嵌入式硬件
落羽的落羽12 小时前
【C++】C++17的主要特性
linux·服务器·开发语言·c++·算法·机器学习
爱和冰阔落17 小时前
【Linux网络】TCP 半包粘包怎么解决?从长度报头、JSON 拆包到网络计算器完整实战
linux·运维·网络·tcp/ip