环境:
Ubuntu14-4 内核 4.4.0-135
vim编辑器 7.4
gcc 4.8.4
1.1 知识点
Shell 的基本概念
进程控制相关的系统调用的使用(如 fork,exec函数族)
整理框架:
1.命令解释器首先是一个死循环。
2.打印一个命令提示符。
3.取得命令行输入放在数组里面,要求命令带参数。可以getc()、fgets()、scanf()等。
4.如果用fgets()的话,取得的字符串包括最后输入的换行符,故要去掉命令字符串末尾的“/n”,变成“/0”。
5.用字符串切割函数将得到的命令行以空格切割存储在字符串数组中。
6.创建一个子进程,调用exec执行命令,将切割得到的命令以及参数传入。
7.父进程调用waitpid()等待子进程的退出,然后进入下一次循环。
bash终端部分:
#include
#include
#include
#include
#include
#include
#include
#include
#include
#define STRLEN 128
//命令行提示符
void PrintfFlag()
{
struct passwd *pw=getpwuid(getuid());//得到当前用户的名称的结构体指针pw
assert(pw!=NULL);
struct utsname un;//得到主机标识
uname(&un);
//assert(uname!=NULL);
char shortname[STRLEN]={0};
memmove(shortname,un.nodename,9);
char path[STRLEN]={0};//得到当前工作路径
getcwd(path,STRLEN-1);
char *p=path;
if(strcmp(path,"/")==0)
{
p="/";
}
//else if(strcmp(p,getenv("HOME"))==0)
else if(strcmp(p,pw->pw_dir)==0)
{
p="~";
}
else
{
p=path+strlen(path);
while(*p--!='/');
p+=2;
}
char flag='$';//得到当前用户状态
if(getuid()==0)
{
flag='#';
}
printf("[%s@%s %s]%c ",pw->pw_name,shortname,p,flag);
}
void CutCmd(char *cmd,char *argv[])
{
int count=0;
char *p=strtok(cmd," "); //以空格分割cmd,将得到的字符串存储在argv字符串数组中
while(p!=NULL)
{
argv[count++]=p;
if(count==STRLEN)
{
break;
}
p=strtok(NULL," ");
}
}
void CdCmd(char *path)
{
static char PrePath[STRLEN]={0}; //静态区存储上一次目录
struct passwd*pw=NULL;
if(strcmp(path,"~")==0)
{
pw=getpwuid(getuid());
assert(pw!=NULL);
path=pw->pw_dir;
}
else if(strcmp(path,"-")==0)
{
if(strlen(PrePath)==0)
{
printf("OLDPWD not set\n");
return ;
}
path=PrePath;
}
char NowPath[STRLEN]={0};
getcwd(NowPath,STRLEN-1); //获得当前工作目录
if(-1==chdir(path)) //工作目录转移
{
printf("bash: cd: %s: No such file or director\n",path);
}
else
{
strcpy(PrePath,NowPath);
}
}
int main()
{
while(1)
{
PrintfFlag();
char cmd[STRLEN] = {0};
fgets(cmd,STRLEN,stdin);// 输入命令
cmd[strlen(cmd) - 1] = 0;
if(strlen(cmd) == 0)
{
continue;
}
if(strcmp(cmd,"exit") == 0)
{
exit(0);
}
char *argv[STRLEN] = {0};
CutCmd(cmd,argv); //比如:argv[0]="ls",argv[1]="-al",argv[2]=getcwd();
if(strcmp(argv[0],"cd") == 0)
{
CdCmd(argv[1]);
continue;
}
pid_t pid=fork();
assert(pid != -1);
if(pid == 0)
{
char path[STRLEN] = {"/home/zhao/Desktop/shell/bin/"};
if(strstr(argv[0],"/") != NULL)//防止带路经命令引起路径错误
{
memset(path,0,STRLEN);
}
strcat(path,argv[0]);
execv(path,argv);
printf("bash: %s: command not found\n",argv[0]);
exit(0); //当exec函数调用失败时,子进程能够安全推出
}
else
{
wait(NULL);
}
}
return 0;
}