版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/Ferlan/article/details/82781662
1 /* 模拟shell写一个咱们自己的微型myshell
2 * 功能:myshell> ls
3 * 能够执行各种命令
4 *
5 */
6 #include <stdio.h>
7 #include <unistd.h>
8 #include <stdlib.h>
9 #include <errno.h>
10 #include <string.h>
11 //1. 获取终端输入
12 //2. 解析输入(按空格解析到一个一个的命令参数)
13 //3. 创建一个子进程
14 // 在子进程中进行程序替换,让子进程运行命令
15 //4. 等待子进程运行完毕,收尸,获取退出状态码
16 //
17 int argc;//用来记录命令行参数的个数
18 char *argv[32];//用来保存各个命令行参数
19 int param_parse(char *buff)//用于实现从buff中分离出各个命令行参数并保存在argv中
20 {
21 //ls -l -a
22 if (buff == NULL)
23 return -1;
24 char *ptr = buff;//利用ptr遍历buff
25 char *tmp = ptr;//利用tmp标记每个命令行参数的开始位置(命令行之间用空格隔开)
26 argc = 0;
27 while((*ptr) != '\0') {
28
29
31 if (*ptr == ' ' && *(ptr+1) != ' ') {
32 //只有当读取到空格且下个字符不为空格时才表明已经完整的读取了一个字符串,由tmp标记
33 //若未进入循环,要么是命令行参数未读完,要么是遇到了多个空格,都接着读即可。
34 *ptr = '\0';
35 argv[argc] = tmp;//将tmp标记的字符串存入argv数组
36 tmp = ptr + 1;//让tmp标记下一个命令行参数的开始位置
37 argc++;//命令行参数个数+1
38 }
39 ptr++;
40 }
41
42 argv[argc++] = tmp;//当ptr已经到‘\0’时,最后一个命令行参数不要忘了了也存入argv数组
43 argv[argc] = NULL;//execvp要以“NULL”作为最后一个参数。
44 return 0;
45 }
46
47 int exec_cmd()//创建一个子进程,并用exec函数替换
48 {
49 int pid = 0;
50
51 pid = fork();
52 if (pid < 0) {
53 perror("fork");
54 return -1;
55 }else if (pid == 0) {//child
56 execvp(argv[0], argv);
57 exit(0);
58 }
59 //父进程在这里必须等待子进程退出,来看看子进程为什么退出了
60 //是不是出现了什么错误,通过获取状态码,并且转换一下退出码所
61 //对应的错误信息进行打印
62 int statu;
63 wait(&statu);
64 //判断子进程是否是代码运行完毕退出
65 if (WIFEXITED(statu)) {
66 //获取到子进程的退出码,转换为文本信息打印
67 printf("%s\n", strerror(WEXITSTATUS(statu)));
68 }
69 return 0;
70 }
71 int main()
72 {
73 while(1) {
74 printf("myshell> ");
75 char buff[1024] = {0};
76 // %[^\n] 获取数据直到遇到\n为止
77 // %*c 清空缓冲区,数据都不要了
78 scanf("%[^\n]%*c", buff);
79 printf("%s\n", buff);
80 param_parse(buff);
81 exec_cmd();
82 }
83 return 0;
84 }