我们如果要写一个简易的shell我们要,其实我们搞一个程序替换就行了。
我们分为五部完成
在其中我们最难搞的就是环境变量的更新,因为当我们搞一个子程序出来时,我们子进程的环境变量表是从父进程继承下来的,当我们用cd命令时只会更改子进程的cwd,而不会改变系统shell的cwd。因为cd命令本是是一个自建命令(我认为的自建命令就会改变环境变量的命令),而遇到cd这样的命令我们需要手动更改shell的cwd,就是做一个特殊处理。而当我们每次更改后我们也需要手动更改我们自己myshell的pwd环境变量。
重点一:更新pwd
我们在每次获取系统shell的pwd时,还需要手动修改一下自己env的pwd
说实话直接讲会很晦涩不如源码自己研究
我这里直接展现源码:
#include<iostream>
#include<cstdio>
#include<cstring>
#include<string>
#include<cstdlib>
#include<unistd.h>
#include <sys/types.h>
#include <sys/wait.h>
extern char**environ;
using namespace std;
const int maxsize=1024;
//获取命令提示:
char comandInfo[maxsize];
int comandInfoSize=0;
//获取命令
char getComand[maxsize];
//处理后的命令
char *gargv[64];
int gargc=0;
//获取shell的pwd
char pwd[maxsize];
//更新pwdenv
char pwdenv[maxsize];
//为子进程创建环境变量
char *env[64];
string getNAME()
{
string name=getenv("USER");
if(name.empty())
{
return "NONE";
}
return name;
}
string getHOSTNAME()
{
string hostname=getenv("HOSTNAME");
if(hostname.empty())
{
return "NONE";
}
return hostname ;
}
string getPWD()
{
getcwd(pwd,sizeof(pwd));
snprintf(pwdenv,sizeof(pwdenv),"PWD=%s",pwd);
putenv(pwdenv);
return pwd;
}
string MakeComandInfo()
{
snprintf(comandInfo,maxsize,"[%s@%s %s]*",getNAME().c_str(),getHOSTNAME().c_str(),getPWD().c_str());
return comandInfo;
}
void printComandInfo()//打印命令提示
{
memset(comandInfo,0,sizeof(comandInfo));
printf("%s",MakeComandInfo().c_str());
fflush(stdout);
}
bool GetComand()
{
char*str= fgets(getComand,maxsize,stdin);
if(str==NULL)
return false;
getComand[strlen(str)-1]=0;
return true;
}
void HandComand()
{
gargc=0;
memset(gargv,0,sizeof(gargv));
char buff[]=" ";
gargv[gargc++]= strtok(getComand,buff);
while(gargv[gargc++]=strtok(NULL,buff));
gargc--;
}
void debug()
{
//printf("%d\n",strlen(env[1]));
for(int i=0;env[i];i++)
{
printf("argv[%d]:%s\n",i,gargv[i]);
}
}
void MyShell()
{
execvpe(gargv[0],gargv,env);
exit(0);
}
void run()
{
pid_t id=fork();
if(id==0)
{
MyShell();
exit(1);
}
else if(id>0)
{
int status=0;
pid_t cid=waitpid(id,&status,0);
}
}
bool CheckBiuldComand()
{
if(strcmp("cd",gargv[0])==0)
{
if(gargc==2)
{
for(int i=0;environ[i];i++)
if(strncmp(environ[i],"PWD",3)==0)
cout<<environ[i]<<endl;
chdir(gargv[1]);
}
return true;
}
return false;
}
void Initenv()
{
int i;
for(i=0;environ[i];i++)
{
//cout<<environ[i]<<endl;
env[i]=(char*)malloc(strlen(environ[i]+1));
strncpy(env[i],environ[i],strlen(environ[i]));
}
env[i]=nullptr;
}
int main()
{
while(1)
{
Initenv();
printComandInfo(); //打印命令提示
// MakeComandInfo();
if( GetComand()==false) continue; //获取用户输入信
HandComand(); //分析命令
//vardebug();
if(CheckBiuldComand()) continue; //判断是否为内建命令
run(); //执行命令
}
return 0;
}