我门用exec函数来写一个简易版的shell
我们先理一下步骤:
-
首先将输入的在命令解析为一个一个的命令,就去掉空格,我们可以使用strtok函数(创建命令)
-
然后在创建一个进程让它去执行这个命令(解析命令并执行)
-
父进程等待进程结束了返回之后,继续执行原来的代码
#include <stdio.h>
#include <sys/types.h>
#include <pwd.h>
#include <unistd.h>
#include <string.h>
#include <ctype.h>
#include <stdlib.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <wait.h>
void GetLocalName()
{
struct passwd *pass;
pass = getpwuid(getuid());
printf("[%s@",pass->pw_name);
}
void GetHostName()
{
char name[128];
//将得到的主机名放在数组里
gethostname(name,sizeof(name)-1);
printf("%s",name);
}
void GetDir()
{
char pwd[256];
getcwd(pwd,sizeof(pwd)-1);
int len = strlen(pwd);
//得到该程序执行的根目录
char *p = pwd + len -1;
while(*p != '/'&& len--)
{
p--;
}
p++;
printf(" %s]@",p);
}
int main()
{
while(1)
{
//打印目录信息和主机名和什么地址
GetLocalName();
GetHostName();
GetDir();
//刷新输出缓冲区
fflush(stdout);
char buf[1024];
ssize_t s = read(0,buf,1024);
//读到了字符
if(s > 0)
{
//在最后添一个'\0',使之成为字符串
buf[s-1] ='\0';
}
else
{
perror("read error!");
}
//将读到的字符按空格拆分放入一个指针数组
char *argv[100] = {NULL};
char *p = strtok(buf," ");
int size = 0;
while(p != NULL)
{
argv[size++] = p;
p = strtok(NULL," ");
}
argv[size] = NULL;
//开始让子进程去执行我们输入的命令,执行完成之后,再返回执行父进程
pid_t id = fork();
if(id == 0)
{
//子进程
// exec
execvp(argv[0],argv);
exit(1);
}
else if(id < 0)
{
perror("fork error!\n");
}
else
{
//父进程等待子进程执行完再继续执行父进程
int status = 0;
pid_t ret = waitpid(id,&status,0);
if(ret > 0 && WIFEXITED(status))
{}
else
{
perror("waitpid error!\n");
}
}
}
}
这个代码其实逻辑也比较简单,但是这个shell真的是太简单了,没有管道和重定向,还有一些内键指令也没有,但是这只是搭建出来了一个shell的结构,接下来这些东西还要自己去添加
修改了简易版的shell使之支持了管道重定向和内键指令,代码就不贴了,我把它提交到码云上了,下面贴上我的码云链接