shell 命令解释器:
bash ./bash
测试: ls /cp /pwd
ls.c/cp.c/pwd.c
bash 是不会通过exit退出的。
cd/exit等等,属于内置命令 ./只能在父进程直接实现。/只能对当前进程进行操作。[exit是把当前进程进行退出)(所以不能通过fork() + exec 实现,子进程不能通过exit结束父进程)是通过函数,方法实现的,没有在系统中。
而ls/cp等只是对文件进行查看和拷贝,所以无论是父进程还是子进程都能完成。
strtok() 可以记住和上一个分割的位置(全局,静态实现)
模拟:
stu@stu-virtual-machine:~/linux/day6/bash$
- get_cmd() 将输入的 字符串分割,并返回ptr指向的第一个字符
//通过 man getpwuid 来查找具体获取用户名等方法。
1 #include<stdio.h>
2 #include<stdlib.h>
3 #include<unistd.h>
4 #include<string.h>
5 #include<sys/wait.h>
6 #include<pwd.h>
7 #define ARG_MAX 10
8 char* get_cmd(char buff[],char*myargv[])//解析命令
9 {
10 if(buff == NULL||myargv == NULL)
11 {
12 return NULL;
13 }
14
15 int i = 0;
16 char*s = strtok(buff," "); //strtok会自动记录分割的位置,定义静态变量 全局变量
17 while(s != NULL)
18 {
19 myargv[i++] = s;
20 s = strtok(NULL," "); //把空格替换成\0,
21 }
22 return myargv[0];
23 }
- 创建一个新进程执行字符
24 void run_cmd(char*path,char* myargv[])//运行命令
25 {
26
27 if(path == NULL || myargv == NULL)
28 {
29 return;
30
31 }
32 pid_t pid = fork();
33 if(pid == -1)
34 {
35 return ;
36 }
37 if(pid == 0)
38 {
39 execvp(path,myargv);
40 perror("cmd err");
41 exit(0);
42 }
43 int val = 0;
44 wait(&val);
45
46
47 }
- 输出
48 void print_info()
49 {
50 //判断用户是普通用户还是管理员
51 //通过uid来判断
52 char *user_str = "$";
53 int user_id = getuid();
54 if(user_id == 0)
55 {
56 user_str ="#";
57 }
58 struct passwd* ptr = getpwuid(user_id);
59 if(ptr == NULL)
60 {
61 printf("mybash1.0>>");
62 fflush(stdout);
63 return;
64 }
65 char hostname[128] = {0};
66 if(gethostname(hostname,128)==-1)
67 {
68 printf("mtbash1.0>>");
69 fflush(stdout);
70 return;
71 }
72 char dir[256] = {0};
73 if( getcwd(dir,256) == NULL)//得到当前位置
74 {
75 printf("mybash1.0>>");
76 fflush(stdout);
77 return ;
78 }
79 printf("\033[1;32m%s@%s\033[0m \033[1;34m%s\033[0m%s",ptr->pw_name,hostname,dir,user_str);
80 fflush(stdout);
81 }
- strcmp函数:
strcmp比较两个字符串的大小,一个字符一个字符比较,按ASCLL码比较.
标准规定:
第一个字符串大于第二个字符串,则返回大于0的数字
第一个字符串等于第二个字符串,则返回0
第一个字符串小于第二个字符串,则返回小于0的数字.
82 int main()
83 {
84 while(1)
85 {
86 print_info();
87 char buff[128]={0}; //一次只输入一个命令
88 fgets(buff,128,stdin);//输入的时候每个命令之间用空格或者逗号间隔
89 buff[strlen(buff)-1] = 0;//去掉fgets回车获得的\n
90
91 char* myargv[ARG_MAX] = {0};//对myargv中的ls/ps/cp/等进行解析
92 char*cmd = get_cmd(buff,myargv);
93 if(cmd == NULL)
94 {
95 continue;
96 }
97 else if(strcmp(cmd,"exit")==0)
98 {
99 break;
100 }
101 else if(strcmp(cmd,"cd")==0)
102 {
103 break;
104 }
105 else
106 {//fork+excv
107
108 run_cmd(cmd,myargv);
109 }
110
111 }
112 exit(0);
113
114 }
其中的很多功能,其实都可以手工实现。