目录
写个简单shell
shell(bash)也是一个进程
死循环执行以下操作
- 命令行提示符
- 获取命令行
- 分析命令
- 执行命令
命令行提示符
环境变量获取用户,地址
getenv获取环境变量 ,不存在返回空,注意情况
fflush刷新缓冲区
获取用户命令
我们要把用户输入的命令行,当做一个完整的字符串
可以用getline 或者 fgets
这次用fgets,当然getline更简单
用户输入回车,获取的字符串会带\n要处理一下吧
分析命令
用strtok来分割字符串,先分隔成字符串数组
执行命令
让子进程去执行
- 执行命令 exec*
- 退出 exit(),当走到这肯定没有执行成功,因为程序替换成功就没有exit了
cd命令有问题,因为子进程执行完cd我们退出来是在父进程,还是原来的路径,要改的是父进程的pwd
所以得出有些命令必须由子进程执行,有些命令,要由shell自己执行—内建命令 built command
内建命令
所以要加一个步骤,检查是否是内建命令,是就自己执行,
shell自己执行命令,本质是shell调用自己的函数,内建命令很少差不多占5%
内建命令:cd = chdir echo export要修改环境变量的PWD。要我们自己的shell去维护
getcwd 获取当前工作路径
环境变量要shell自己维护
作为一个shell,获取环境变量应该从系统的配置来
我们今天就直接从父shell中获取环境变量
本地变量表 : a=100 这种不能通过环境变量和命令行参数传给子进程,但是可以echo$a所以echo也是内建命令
代码
#include<cstdio>
#include<iostream>
#include<cstdlib>
#include<string>
#include<unistd.h>
#include<string.h>
#include<sys/wait.h>
using namespace std;
#define identif "(•́へ•́☆)*哎哟不错哦"
int buffermax = 1024;
//输出的缓冲区
char* printbuffer = (char*)malloc(sizeof(char)*buffermax);
//获取输入的缓冲区
char* scanfbuffer = (char*)malloc(sizeof(char)*buffermax);
//命令行参数
int gargc = 0;
char** gargv = (char**)malloc(sizeof(char)*buffermax);
char* getname()
{
return getenv("USER");
}
char* gethostname()
{
return getenv("HOSTNAME");
}
char* getpwd()
{
return getenv("PWD");
}
void PrintCommandLine()
{
//[xjh@hcss-ecs-769a learnclass5--myshell]$
snprintf(printbuffer,buffermax,"%s@%s %s",getname(),gethostname(),getpwd());
printf("[%s]%s",printbuffer,identif);
fflush(stdin);
}
void GetCommandLine()
{
memset(scanfbuffer,0,buffermax);
fgets(scanfbuffer,buffermax,stdin);
//去换行符
int s = strlen(scanfbuffer);
scanfbuffer[s-1] = 0;
}
void AnalyseCommandLine()
{
gargc = 0;
memset(gargv,0,buffermax);
//分割命令
gargv[gargc++] = strtok(scanfbuffer," ");
while((bool)(gargv[gargc] = strtok(NULL," ")))
{
gargc++;
}
}
void ExeCommandLine()
{
pid_t id = fork();
//让子进程去执行命令
if(id == 0)
{
//因为又命令行列表所以使用带v,并且gargv[0]就是地址所以带p我们使用execvp
int ret = execvp(gargv[0],gargv);
//由于程序替换走不到exit所以如果程序替换失败了会有返回-1;
exit(ret);
}
//父进程
int status = 0;
int rid = waitpid(id,&status,0);
if(rid > 0)
{
}
}
bool BuiitCommandLine()
{
if(strcmp(gargv[0],"cd")==0)
{
if(gargv[1])
{
chdir(gargv[1]);
//环境变量缓冲区
char* cwd = (char*)malloc(sizeof(char)*buffermax);
char tmp[buffermax];
getcwd(tmp,sizeof(tmp));
snprintf(cwd,buffermax,"PWD=%s",tmp);
putenv(cwd);
}
return true;
}
return false;
}
int main()
{
while(true)
{
//打印命令行提示符
PrintCommandLine();
//获取用户命令
GetCommandLine();
if(!strlen(scanfbuffer))
continue;
//分析命令
AnalyseCommandLine();
//内建命令
if(BuiitCommandLine())
continue;
//执行命令
ExeCommandLine();
}
return 0;
}