💓博主CSDN主页:麻辣韭菜-CSDN博客💓
⏩专栏分类:http://t.csdnimg.cn/G90eI⏪
🚚代码仓库:Linux: Linux日常代码练习🚚
🌹关注我🫵带你学习更多Linux知识
🔝🔝
目录
一.命令行提示信息
二.获取用户输入的字符串
三.拆解用户输入的字符串
四.子进程程序替换
五.内建命令(内置命令)
想想Xshell的命令解释器,我们在命令行输入ls命令,他的父进程是谁?bash 。根据之前的讲的进程替换,根据这个原理父进程当个监工,让子进程去做一些其他事情。
一.命令行提示信息
我们在Linux在命令行输入各种指令是需要提示行的。如下图
而且这个提示行我们不输入他是一只存在的,那就说明了他是一个无限循环的程序->常驻的进程。
按照上面的这个代码 一直打印如下图,那肯定不行。
int main()
{
while(1)
{
//1. 打印出提示信息 [root@localhost myshell]#
printf("[root@localhost myshell]# ");
fflush(stdout);
}
return 0;
}
有了提示信息,我们就要获取用户输入指令,如何获取?用fgets获取 用户输入的指令 我们需要建立一个缓冲区来接受和保存。
二.获取用户输入的字符串
#define NUM 1024
//保存完整的命令行字符串
char cmd_line[NUM]; //用来保存用户输入的字符串
int main()
{
while(1)
{
//1. 打印出提示信息 [root@localhost myshell]#
printf("[root@localhost myshell]# ");
fflush(stdout);
//初始化缓冲区数组
memset(cmd_line, '\0', sizeof cmd_line);
//2. 获取用户的键盘输入[输入的是各种指令和选项: "ls -a -l -i"]
//如果用户输入错误重新开始
if(fgets(cmd_line, sizeof cmd_line, stdin) == NULL)
{
continue;
}
}
return 0;
}
想一想我们在命令行输入各种指令,最后会输入一个回车键,那fgets这个函数也接收到回车键->"\n" 所以我们还需要将回车键设置成"\0"。
#define NUM 1024
//保存完整的命令行字符串
char cmd_line[NUM]; //用来保存用户输入的字符串
int main()
{
while(1)
{
//1. 打印出提示信息 [whb@localhost myshell]#
printf("[root@localhost myshell]# ");
fflush(stdout);
//初始化缓冲区数组
memset(cmd_line, '\0', sizeof cmd_line);
//2. 获取用户的键盘输入[输入的是各种指令和选项: "ls -a -l -i"]
//如果用户输入错误重新开始
if(fgets(cmd_line, sizeof cmd_line, stdin) == NULL)
{
continue;
}
cmd_line[strlen(cmd_line)-1] = '\0';
}
return 0;
}
三.拆解用户输入的字符串
#define NUM 1024
#define SEP " " //定义分割标识符
#define SIZE 64
//保存完整的命令行字符串
char cmd_line[NUM]; //用来保存用户输入的字符串
//保存被打散的字符串
char* g_argv[SIZE];
int main()
{
while(1)
{
//1. 打印出提示信息 [root@localhost myshell]#
printf("[root@localhost myshell]# ");
fflush(stdout);
//初始化缓冲区数组
memset(cmd_line, '\0', sizeof cmd_line);
//2. 获取用户的键盘输入[输入的是各种指令和选项: "ls -a -l -i"]
//如果用户输入错误重新开始
if(fgets(cmd_line, sizeof cmd_line, stdin) == NULL)
{
continue;
}
cmd_line[strlen(cmd_line)-1] = '\0';
//3.命令行字符串解析
g_argv[0] = strtok(cmd_line,SEP); //第一次调用,要传入原始字符串
int index = 1;
while(g_argv[index++] = strtok(NULL,SEP));
}
四.子进程程序替换
#define NUM 1024
#define SEP " " //定义分割标识符
#define SIZE 64
//保存完整的命令行字符串
char cmd_line[NUM]; //用来保存用户输入的字符串
//保存被打散的字符串
char* g_argv[SIZE];
int main()
{
while(1)
{
//1. 打印出提示信息 [root@localhost myshell]#
printf("[root@localhost myshell]# ");
fflush(stdout);
//初始化缓冲区数组
memset(cmd_line, '\0', sizeof cmd_line);
//2. 获取用户的键盘输入[输入的是各种指令和选项: "ls -a -l -i"]
//如果用户输入错误重新开始
if(fgets(cmd_line, sizeof cmd_line, stdin) == NULL)
{
continue;
}
cmd_line[strlen(cmd_line)-1] = '\0';
//3.命令行字符串解析
g_argv[0] = strtok(cmd_line,SEP); //第一次调用,要传入原始字符串
int index = 1;
while(g_argv[index++] = strtok(NULL,SEP));
//4.创建子进程
pid_t id = fork();
if(id <0)
{
perror("fork");
exit(1);
}
if(id == 0)
{
printf("下面功能让子进程进行的\n");
execvp(g_argv[0], g_argv); // ls -a -l -i
exit(1);
}
//father
int status = 0;
pid_t ret = waitpid(id, &status, 0);
if(ret > 0) printf("exit code: %d\n", WEXITSTATUS(status));
}
}
运行没问题 这就完了吗?还没有 内建命令。
仔细看会发现 我们的cd命令没用啊,进入上级路径压根没有变化,那是因为子进程收到cd字这个字符串,是子进程的路径在发生变化运行完毕后了退出了,父进程压根就没有变还是当前路径。
五.内建命令(内置命令)
//5.内置命令, 让父进程(shell)自己执行的命令,我们叫做内置命令,内建命令
//内建命令本质其实就是shell中的一个函数调用
if(strcmp(g_argv[0], "cd") == 0)
{
if(g_argv[1] != NULL) chdir(g_argv[1]);//chdir 可以帮我们自动切换到指定路径
continue;
}
//这段代码放在字符串分割下面
为什么要程序替换,说简单点场景需要,举一个简单的例子:你在抖音上看直播,这个直播间在卖东西,上链接叫你赶紧拍,你在拍东西过程中,直播间你是没有退出的,但是你下单确认支付的那一瞬间,这时另一个进程就开始了 收你钱。