智一面初中级LInux运维工程师在线评测:http://www.gtalent.cn/exam/interview/eUrdXoILlsGnh6At
一、shell是什么?
从零开始编写一个minishell: 1.shell:命令行解释器 2.捕捉键盘输入:scanf,fgets,gets 3.解析输入信息-命令名称,运行参数 4.创建子进程:fork 让子进程执行对应命令名称的程序(程序替换):execvp 子进程程序替换失败必须退出,成功运行完命令程序会自己退出:exit 等待子进程退出:wait
二、minishell的实现
1.捕捉键盘输入
简单示例
代码如下(示例):
1 #include<stdio.h>
2 #include<unistd.h>
3 #include<stdlib.h>
4 #include<string.h>
5 int main(int argc, char* argv[])
6 {
7 while(1){
8 printf("[user@host path]$ ");
9 fflush(stdout);
10 char buf[1024] = {0};
11 fgets(buf, 1023, stdin);
12 printf("cmd:[%s]\n", buf);
13 }
14 return 0;
15 }
简单运行结果
完善之后:
12 buf[strlen(buf) - 1] = '\0';
13 int myargc = 0;
14 char *ptr = buf, *myargv[32] = {NULL};
15 while(*ptr != '\0'){
16 if(*ptr != ' '){
17 myargv[myargc] = ptr;
18 myargc++;
19 while(*ptr != '\0' && *ptr != ' ') ptr++;
20 *ptr = '\0';
21 }
22 ptr++;
23 }
24 myargv[myargc] = NULL;
25 int i = 0;
26 for(i = 0;i < myargc;i++){
27 printf("[%s]\n", myargv[i]);
28 }
2.创建进程
26 pid_t pid = fork();
27 if(pid < 0){
28 perror("fork error");
29 continue;
30 }else if(pid == 0){
31 execvp(myargv[0], myargv);
32 perror("execvp error");
33 exit(-1);
34 }
35 wait(NULL);
但此时切换路径时切换不了的(cd无效), 所以此时只能调用函数改变当前的工作路径
26 if(strcmp("cd", myargv[0]) == 0){
27 chdir(myargv[1]);
28 continue;
29 }
3.在minishell中加上重定向功能
在我们自己实现的minishell中加入重定向功能 >> / >
1.捕捉键盘输入;
1.5解析重定向(判断有没有'>'符号)
1.6将重定向符号之前信息按照以前的命令处理方式进行处理
1.7取出重定向的文件名称
2.解析输入(得到命令名称+参数);
3.创建子进程;
3.5在程序替换之前进行标准输出重定向到指定的文件,open, dup2
4.在子进程中进行程序替换;
5.父进程进行程序等待;
重定向或者文件的信息并不会随着程序替换而消失
20 int direct_flag = 0;//0-没有重定向,1-清空重定向,2-追加重定向
21 char *ptr = buf;
22 char *redirect_file = NULL;
23 while(*ptr != '\0'){
24 if(*ptr == '>'){
25 direct_flag = 1;
26 *ptr = '\0';
27 ptr++;
28 if(*ptr == '\0'){
29 direct_flag = 2;
30 *ptr = '\0';
31 ptr++;
32 }
33 while(*ptr != '\0' && *ptr == ' ') ptr++;
34 redirect_file = ptr;
35 while(*ptr != '\0' && *ptr != ' ') ptr++;
36 *ptr = '\0';
37 }
38 ptr++;
39 }
40 ptr = buf;
62 if(direct_flag == 1){
63 int fd;
64 fd = open(redirect_file, O_CREAT|O_RDWR|O_TRUNC, 0664);
65 dup2(fd, 1);
66 }else if(direct_flag == 2){
67 int fd;
68 fd = open(redirect_file, O_CREAT|O_RDWR|O_APPEND, 0664);
69 dup2(fd, 1);
70 }
4.整体代码
1 #include<stdio.h>
2 #include<stdlib.h>
3 #include<unistd.h>
4 #include<string.h>
5 #include<ctype.h>
6 #include<fcntl.h>
7 #include<sys/stat.h>
8 #include<sys/wait.h>
9 int main(int argc,char *argv[])
10 {
11 while(1){
12 printf("[user@host path]$ ");
13 fflush(stdout);//手动刷新缓冲区
14 char buf[1024] = {0};
15 fgets(buf, 1023, stdin);
16 buf[strlen(buf) - 1] = '\0';
17
18
19
20 int direct_flag = 0;//0-没有重定向,1-清空重定向,2-追加重定向
21 char *ptr = buf;
22 char *redirect_file = NULL;
23 while(*ptr != '\0'){
24 if(*ptr == '>'){
25 direct_flag = 1;
26 *ptr = '\0';
27 ptr++;
28 if(*ptr == '\0'){
29 direct_flag = 2;
30 *ptr = '\0';
31 ptr++;
32 }
33 while(*ptr != '\0' && *ptr == ' ') ptr++;
34 redirect_file = ptr;
35 while(*ptr != '\0' && *ptr != ' ') ptr++;
36 *ptr = '\0';
37 }
38 ptr++;
39 }
40 ptr = buf;
41 char *myargv[32] = {NULL};
42 int myargc = 0;
43 while(*ptr != '\0'){
44 if(*ptr != ' '){
45 myargv[myargc] = ptr;
46 myargc++;
47 while(*ptr != '\0' && *ptr != ' ') ptr++;
48 *ptr = '\0';
49 }
50 ptr++;
51 }
52 myargv[myargc] = NULL;
53 if(strcmp("cd", myargv[0]) == 0){
54 chdir(myargv[1]);
55 continue;
56 }
57 pid_t pid = fork();
58 if(pid < 0){
59 perror("fork error");
60 continue;
61 }else if(pid == 0){
62 if(direct_flag == 1){
63 int fd;
64 fd = open(redirect_file, O_CREAT|O_RDWR|O_TRUNC, 0664);
65 dup2(fd, 1);
66 }else if(direct_flag == 2){
67 int fd;
68 fd = open(redirect_file, O_CREAT|O_RDWR|O_APPEND, 0664);
69 dup2(fd, 1);
70 }
71 execvp(myargv[0],myargv);
72 perror("execvp error");
73 exit(-1);
74 }
75 wait(NULL);
76 }
77 return 0;
78 }
运维工程师QQ在线交流群:580175957