0
点赞
收藏
分享

微信扫一扫

模拟实现Bash

模拟实现Bash

1.Bash基本认识

2.Bash实现

#include <stdio.h>
#include <string.h>
#include <iostream>
#include <stdlib.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/wait.h>
using namespace std;

char* commend_list[10]={NULL};
int main()
{
    char commend[1024];//将命令存入这个数组
    while(1)
    {
        cout<<"[lnb@VM-16-17centos 当前目录]";
        fgets(commend,1024,stdin);
        //去掉\n
        commend[strlen(commend)-1]='\0';
        //拆分命令
        commend_list[0]=strtok(commend," ");
        int i=1;
        while(commend_list[i++]=strtok(NULL," "))
        {}

        // i=0;
        // while(commend_list[i])        
        // {
        //     cout<<commend_list[i++]<<endl;
        // }
        
        //创建子进程
        pid_t ret=fork();
        if(ret>0)
        {
            //父进程,进行等待
            int status=0;
            waitpid(ret,&status,0);
            cout<<"退出信号:"<<(status&0x7f)<<",退出码:"<<((status>>8)&0xff)<<endl;
            cout<<"退出信号:"<<WTERMSIG(status)<<",退出码:"<<WEXITSTATUS(status)<<endl;
        }
        else
        {
            //子进程,进行程序替换
            execvp(commend_list[0],commend_list);
            exit(-1);
        }
    }
    return 0;
}

3.添加细节

#include <stdio.h>
#include <string.h>
#include <iostream>
#include <stdlib.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/wait.h>
using namespace std;

char* commend_list[10]={NULL};
int main()
{
    char commend[1024];//将命令存入这个数组
    while(1)
    {
        cout<<"[lnb@VM-16-17centos 当前目录]";
        fgets(commend,1024,stdin);
        //去掉\n
        commend[strlen(commend)-1]='\0';
        //拆分命令
        commend_list[0]=strtok(commend," ");
        int i=1;
        while(commend_list[i++]=strtok(NULL," "))
        {}

        // i=0;
        // while(commend_list[i])        
        // {
        //     cout<<commend_list[i++]<<endl;
        // }
        
     

        if(strcmp(commend_list[0],"ls")==0)
        {
            commend_list[i++]="--color=auto";
        }
        if(strcmp(commend_list[0],"ll")==0)
        {
            commend_list[0]="ls";
            commend_list[1]="-l";
            commend_list[2]="--color=auto";
            commend_list[3]=NULL;
        }


        //创建子进程
        pid_t ret=fork();
        if(ret>0)
        {
            //父进程,进行等待
            int status=0;
            waitpid(ret,&status,0);
            cout<<"退出信号:"<<(status&0x7f)<<",退出码:"<<((status>>8)&0xff)<<endl;
            cout<<"退出信号:"<<WTERMSIG(status)<<",退出码:"<<WEXITSTATUS(status)<<endl;
        }
        else
        {
            //子进程,进行程序替换
            execvp(commend_list[0],commend_list);
            exit(-1);
        }
    }
    return 0;
}

4.内置命令

#include <stdio.h>
#include <string.h>
#include <iostream>
#include <stdlib.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/wait.h>
using namespace std;

char* commend_list[10]={NULL};
int main()
{
    char commend[1024];//将命令存入这个数组
    while(1)
    {
        cout<<"[lnb@VM-16-17centos 当前目录]";
        fgets(commend,1024,stdin);
        //去掉\n
        commend[strlen(commend)-1]='\0';
        //拆分命令
        commend_list[0]=strtok(commend," ");
        int i=1;
        while(commend_list[i++]=strtok(NULL," "))
        {}

        // i=0;
        // while(commend_list[i])        
        // {
        //     cout<<commend_list[i++]<<endl;
        // }
        
     

        if(strcmp(commend_list[0],"ls")==0)
        {
            commend_list[i++]="--color=auto";
        }
        if(strcmp(commend_list[0],"ll")==0)
        {
            commend_list[0]="ls";
            commend_list[1]="-l";
            commend_list[2]="--color=auto";
            commend_list[3]=NULL;
        }
        if(strcmp(commend_list[0],"cd")==0)
        {
            if(commend_list[1]!=NULL)
            chdir(commend_list[1]);
            continue;
        }


        //创建子进程
        pid_t ret=fork();
        if(ret>0)
        {
            //父进程,进行等待
            int status=0;
            waitpid(ret,&status,0);
            cout<<"退出信号:"<<(status&0x7f)<<",退出码:"<<((status>>8)&0xff)<<endl;
            cout<<"退出信号:"<<WTERMSIG(status)<<",退出码:"<<WEXITSTATUS(status)<<endl;
        }
        else
        {
            //子进程,进行程序替换
            execvp(commend_list[0],commend_list);
            exit(-1);
        }
    }
    return 0;
}

#include <iostream>
#include <unistd.h>
using namespace std;
int main()
{
    putenv("val=100");
    while(1);//使用循环来保证环境变量不会随着程序结束而结束

    return 0;
}
//test.cc
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <iostream>
#include <sys/wait.h>
#include <sys/types.h>
extern char** environ;
int main(int argc,char* argv[],char *envp[])
{
  //std::cout<<(void*)envp<<std::endl;
  //std::cout<<(void*)environ<<std::endl;
  putenv("val=111111111111111111111111111111111111111111111111111");
  for(int i=0;environ[i];i++)
  {
    std:: cout<<environ[i]<<std::endl;
  }

  std::cout<<std::endl<<std::endl<<std::endl<<std::endl;
  
int ret=fork();
if(ret==0)
{
  execl("/home/lnb/linux-l/24_review/24_11_13/replace","./replace");//程序替换成我们自己写的程序来查看环境变量
}
waitpid(ret,NULL,0);//父进程负责等待子进程

while(1)
{

}


  return 0;
}

//relpace.cc
#include <iostream>
using namespace std;
int main(int argc,char* argv[],char* envp[])
{
  for(int i=0;envp[i];i++)  
  {
    cout<<envp[i]<<endl;
  }




  return 0;
}

//test.cc
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <iostream>
#include <sys/wait.h>
#include <sys/types.h>
extern char** environ;
int main(int argc,char* argv[],char *envp[])
{
  std::cout<<(void*)envp<<std::endl;//打印地址
  std::cout<<(void*)environ<<std::endl;//打印地址
  putenv("val=111111111111111111111111111111111111111111111111111");
  for(int i=0;envp[i];i++)
  {
    std:: cout<<envp[i]<<std::endl;
  }

  std::cout<<std::endl<<std::endl<<std::endl<<std::endl;//和子进程打印的结果进行分割
  
int ret=fork();
if(ret==0)
{
  execl("/home/lnb/linux-l/24_review/24_11_13/replace","./replace");//程序替换成我们自己写的程序来查看环境变量
}
waitpid(ret,NULL,0);//父进程负责等待子进程

while(1)
{

}


  return 0;
}

#include <stdio.h>
#include <string.h>
#include <iostream>
#include <stdlib.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/wait.h>
using namespace std;

extern char** environ;

char* commend_list[10]={NULL};
char  environment[20][30]={0};//用来存储用户自己的环境变量
int envir_index=0;
int main()
{
    char commend[1024];//将命令存入这个数组
    while(1)
    {
        cout<<"[lnb@VM-16-17centos 当前目录]";
        fgets(commend,1024,stdin);
        //去掉\n
        commend[strlen(commend)-1]='\0';
        //拆分命令
        commend_list[0]=strtok(commend," ");
        int i=1;
        while(commend_list[i++]=strtok(NULL," "))
        {}

        // i=0;
        // while(commend_list[i])        
        // {
        //     cout<<commend_list[i++]<<endl;
        // }
        
     

        if(strcmp(commend_list[0],"ls")==0)
        {
            commend_list[i++]="--color=auto";
        }
        if(strcmp(commend_list[0],"ll")==0)
        {
            commend_list[0]="ls";
            commend_list[1]="-l";
            commend_list[2]="--color=auto";
            commend_list[3]=NULL;
        }
        if(strcmp(commend_list[0],"cd")==0)
        {
            if(commend_list[1]!=NULL)
            chdir(commend_list[1]);
            continue;
        }

        if(strcmp(commend_list[0],"export")==0)
        {   
            //我们要对这个它添加的环境变量进行一个保存,
            //因为如果不保存会出现环境变量指针消失的问题
            //commend_list[1]中存储了我们的添加的环境变量
            //但是当我们下一回合重新读取命令的时候,他就会
            //被覆盖,因为我们的commend_list数组中的指针都是
            //从commend中出来的,这样的话就会导致结果有问题,
            //无法正常显示
            if(commend_list[1]!=NULL)
            {
                strcpy(environment[envir_index],commend_list[1]);
                putenv(environment[envir_index++]);
                continue;
            }
        }
        
        if(strcmp(commend_list[0],"env")==0)
        {
                //之所以要进行特殊处理env是因为我们要打印显示的是bash父进程本身的环境变量
                //而不是我们的子进程
            for(int i=0;environ[i];i++)
            {
                cout<<environ[i]<<endl;
            }
            continue;
        }
        //创建子进程
        pid_t ret=fork();
        if(ret>0)
        {
            //父进程,进行等待
            int status=0;
            waitpid(ret,&status,0);
            cout<<"退出信号:"<<(status&0x7f)<<",退出码:"<<((status>>8)&0xff)<<endl;
            cout<<"退出信号:"<<WTERMSIG(status)<<",退出码:"<<WEXITSTATUS(status)<<endl;
        }
        else
        {
            //子进程,进行程序替换
            execvp(commend_list[0],commend_list);
            exit(-1);
        }
    }
    return 0;
}

5.完整代码

在下面的完整代码中,我也加入了echo等其他部分的命令的处理,也进行了注释,相信大家也能看得懂

#include <stdio.h>
#include <string.h>
#include <iostream>
#include <stdlib.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/wait.h>
using namespace std;

extern char** environ;

static int ret_code=0;//用来记录上一个进程的退出码

char* commend_list[10]={NULL};
char  environment[20][30]={0};//用来存储用户自己的环境变量
int envir_index=0;
int main()
{
    char commend[1024];//将命令存入这个数组
    while(1)
    {
        cout<<"[lnb@VM-16-17centos 当前目录]";
        fgets(commend,1024,stdin);
        //去掉\n
        commend[strlen(commend)-1]='\0';
        //拆分命令
        commend_list[0]=strtok(commend," ");
        int i=1;
        while(commend_list[i++]=strtok(NULL," "))
        {}

        // i=0;
        // while(commend_list[i])        
        // {
        //     cout<<commend_list[i++]<<endl;
        // }
        
     

        if(strcmp(commend_list[0],"ls")==0)
        {
            commend_list[i++]="--color=auto";
        }
        if(strcmp(commend_list[0],"ll")==0)
        {
            commend_list[0]="ls";
            commend_list[1]="-l";
            commend_list[2]="--color=auto";
            commend_list[3]=NULL;
        }
        if(strcmp(commend_list[0],"cd")==0)
        {
            if(commend_list[1]!=NULL)
            chdir(commend_list[1]);
            continue;
        }

        if(strcmp(commend_list[0],"export")==0)
        {   
            //我们要对这个它添加的环境变量进行一个保存,
            //因为如果不保存会出现环境变量指针消失的问题
            //commend_list[1]中存储了我们的添加的环境变量
            //但是当我们下一回合重新读取命令的时候,他就会
            //被覆盖,因为我们的commend_list数组中的指针都是
            //从commend中出来的,这样的话就会导致结果有问题,
            //无法正常显示
            if(commend_list[1]!=NULL)
            {
                strcpy(environment[envir_index],commend_list[1]);
                putenv(environment[envir_index++]);
                continue;
            }
        }
        
        if(strcmp(commend_list[0],"env")==0)
        {
                //之所以要进行特殊处理env是因为我们要打印显示的是bash父进程本身的环境变量
                //而不是我们的子进程
            for(int i=0;environ[i];i++)
            {
                cout<<environ[i]<<endl;
            }
            continue;
        }

        if(strcmp(commend_list[0],"echo")==0&&(*(commend_list[1]))=='$')//对于查看环境变量值的处理
        {
            if(commend_list[1][1]=='?')//第一个命令选项中第二个字符
            {
                cout<<ret_code<<endl;
                continue;
            }
            const char* str=NULL;
            str=getenv(commend_list[1]+1);//此处的commend_list[1]的值为char*,指向第一个命令选项,+1后指向$后面
            printf("%s:%s\n",commend_list[1]+1,str);
            continue;
        }


        //创建子进程
        pid_t ret=fork();
        if(ret>0)
        {
            //父进程,进行等待
            int status=0;
            waitpid(ret,&status,0);
            cout<<"退出信号:"<<(status&0x7f)<<",退出码:"<<((status>>8)&0xff)<<endl;
            cout<<"退出信号:"<<WTERMSIG(status)<<",退出码:"<<WEXITSTATUS(status)<<endl;
            ret_code=((status>>8)&0xff);
        }
        else
        {
            //子进程,进行程序替换
            execvp(commend_list[0],commend_list);
            exit(-1);
        }
    }
    return 0;
}

举报

相关推荐

模拟new实现

string模拟实现

模拟实现atoi

list模拟实现

string模拟实现:

评论模拟实现

0 条评论