目录
实现思路
循环以下过程:
1. 获取命令行
2. 解析命令行
3. 建立一个子进程(fork)
4. 替换子进程(execvp)
5. 父进程等待子进程退出(wait)
实现代码:
int main()
{
while(1)
{
printf("[用户名@主机名 路径]$ ");
fflush(stdout);//刷新缓冲区
ssize_t n = read(0,lineCommand,sizeof(lineCommand));//将stdin的数据读到lineCommand变量中
assert(n != -1);
lineCommand[strlen(lineCommand)-1]=0;//去掉输入命令时按的\n
//输入指令时会以空格隔开,利用这点提取指令和参数,存在指针数组中
int i = 0;
myargv[i++] = strtok(lineCommand," ");
while(myargv[i++] = strtok(NULL," "));
pid_t id = fork();
if(id < 0)
{
printf("fork fail");
exit(1);
}
if(id == 0)
{//child
execvp(myargv[0],myargv);
exit(1);
}
waitpid(id,NULL,0);
}
return 0;
}
内建命令如何实现
运行上面的代码可以发现cd到上级目录后查看当前路径没有变化,为什么会这样?
首先来了解一下什么是当前路径:
运行一段代码
#include <stdio.h>
#include <string.h>
#include <unistd.h>
int main()
{
pid_t id = fork();
if(id == 0)
{
while(1)
{
printf("我是子进程,pid: %d\n",getpid());
sleep(2);
}
}
return 0;
}
查进程文件
当前路径本质就是进程的工作目录
调用chdir函数可以改变进程的工作目录
修改一下代码
#include <stdio.h>
#include <string.h>
#include <unistd.h>
int main()
{
chdir("/home/wcl");//修改工作目录
pid_t id = fork();
if(id == 0)
{
while(1)
{
printf("我是子进程,pid: %d\n",getpid());
sleep(2);
}
}
return 0;
}
修改成功
回到最初的问题,为什么我们自己写的myshell,cd的时候,路径没有变化呢?原因是:
fork() --->子进程 执行的 cd---> 子进程有自己的工作目录---> 更改的是子进程的目录! --->子进程执行完毕 ---> 继续用的是父进程,即myshell!
将myshell代码修改一下即可实现cd命令
#include <stdlib.h>
#include<assert.h>
#include <stdio.h>
#include <string.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#define NUM 1024
char lineCommand[NUM];
char *myargv[1024];
char buf[1024];
char *route[1024];
int main()
{
while(1)
{
//目前水平不知道怎么获取路径,用了一个不怎么高明的方法,但是总归能解决问题。
int cnt = 0;
getcwd(buf,sizeof(buf));
route[cnt++] = strtok(buf,"/");
while(route[cnt++] = strtok(NULL,"/"));
printf("[%s@%s %s]$ ",getenv("USER"),getenv("HOSTNAME"),route[cnt-2]);
fflush(stdout);//刷新缓冲区
memset(lineCommand,0,sizeof(lineCommand));
ssize_t n = read(0,lineCommand,sizeof(lineCommand));//将stdin的数据读到lineCommand变量中
assert(n != -1);
lineCommand[strlen(lineCommand)-1]=0;//去掉输入命令时按的\n
//输入指令时会以空格隔开,利用这点提取指令和参数,存在指针数组中
int i = 0;
myargv[i++] = strtok(lineCommand," ");
while(myargv[i++] = strtok(NULL," "));
if(myargv[0] != NULL && strcmp(myargv[0],"cd") == 0)
{
if(myargv[1] != NULL) chdir(myargv[1]);//内建命令
continue;
}
pid_t id = fork();
if(id < 0)
{
printf("fork fail");
exit(1);
}
if(id == 0)
{//child
execvp(myargv[0],myargv);
exit(1);
}
waitpid(id,NULL,0);
}
return 0;
}
• 如果是cd命令,不需要创建子进程,让she11自己执行对应的命令,本质就是执行系统接口
• 像这种不需要让我们的子进程来执行,而是让she11自已执行的命令叫做 内建/内置命令
编译运行看看效果
myshell一眼看上去和系统的shell没什么区别,不过myshell没有配色规则。