目录
shell解释器:
就像下面Centos的环境下的命令行,可以解析我们输入的指令来达到运行不同功能的实现;
shelll条件:
必须是永不退出的,常驻内存的,我们使用死循环来解决;
输入的命令又指令和指令选项:ls -a -l,我们使用命令分割来进行区分
命令分割后解析需要子进程来运行解析后的指令对应的进程,这里需要运行其他进程,但是又不能影响父进程,我们创建子进程用execvp进行程序替换,来实现运行不同指令的效果;
一、命令分割
我们需要将输入的指令和选项分割开,方便我们来解析指令;
这里我们采用了字符串函数strtok()来分割
g_argv[0] = strtok(cmd_line, SEP);//第一次调用,传入原始字符串
int index = 1;
if (strcmp(g_argv[0], "ls") == 0)
{
g_argv[index++] = "--color=auto";
}
while(g_argv[index++] = strtok(NULL, SEP));//第二次调用,如果还要解析,传入NUL
二、fork()创建子进程
将命令解析后,创建子进程使用execvp()替换函数,来进行程序替换,实现功能;
这时的父进程只需要等待子进程正常退出即可;
64 //5.fork();
65 pid_t id = fork();
66 if (id == 0)// child
67 {
68 printf("功能子进程执行\n");
69 // cd 只影响当前的进程
70 execvp(g_argv[0], g_argv);//ls -a -l
71 exit(-1);
72 }
73
74 // father
75 int status = 0;
76 pid_t ret = waitpid(id, &status, 0);
77 if (ret > 0)
78 {
79 printf("exit code:%d\n", WEXITSTATUS(status));
80 }
三、全部代码
1 #include <stdio.h>
2 #include <stdlib.h>
3 #include <string.h>
4 #include <unistd.h>
5 #include <sys/wait.h>
6 #include <sys/types.h>
7
8 #define NUM 1024
9 #define SIZE 32
10 #define SEP " "
11
12 //保存打散之后的命令行 字符串
13 char *g_argv[SIZE];
14 //保存完成的命令行
15 char cmd_line[NUM];
16
17 //shell运行原理
18 //通过让子进程执行命令,父进程等待&&解析命令
19 int main()
20 {
21 //0.命令行解释器, 一定是一个常驻内存进程,不退出
22 while (1)
23 {
24 //1.打印提示信息
25 // [mr@localhost myshell]#
26 printf("[my@localhost myshell]#");
27 fflush(stdout);
28 memset(cmd_line, '\0', sizeof cmd_line);
29 //2.获取用户键盘输入的各种指令和选项: “ls -a -l”
30 if (fgets(cmd_line, sizeof cmd_line, stdin) == NULL)
31 {
32 continue;
33 }
34 cmd_line[strlen(cmd_line) - 1] = '\0';
35
36 //printf("echo:%s\n", cmd_line);
37
38 //3.命令行字符串解析
39 g_argv[0] = strtok(cmd_line, SEP);//第一次调用,传入原始字符串
40 int index = 1;
41 if (strcmp(g_argv[0], "ls") == 0)
42 {
43 g_argv[index++] = "--color=auto";
44 }
45 while(g_argv[index++] = strtok(NULL, SEP));//第二次调用,如果还要解析,传入NUL
46
47 // for (index = 0; g_argv[index]; index++)
48 // {
49 // printf("g_argv[%d]:%s\n",index,g_argv[index]);
50 // }
51 //4.TODO 内置命令 :让父进程(shell)自己执行命令,叫做内置命令,内建命令
52 //内建命令本质就是shell中的一个函数调用
53 if (strcmp(g_argv[0], "cd") == 0) //not child excute, father excute
54 {
55 if(g_argv[1] != NULL)
56 {
57 chdir(g_argv[1]);
58
59 continue;
60 }
61 }
62
63
64 //5.fork();
65 pid_t id = fork();
66 if (id == 0)// child
67 {
68 printf("功能子进程执行\n");
69 // cd 只影响当前的进程
70 execvp(g_argv[0], g_argv);//ls -a -l
71 exit(-1);
72 }
73
74 // father
75 int status = 0;
76 pid_t ret = waitpid(id, &status, 0);
77 if (ret > 0)
78 {
79 printf("exit code:%d\n", WEXITSTATUS(status));
80 }
81 }
82
83 return 0;
84 }