先要模拟一个命令行,我们直接使用字符串输出,由于命令行一直需要打印,可以设置一个死循环。之后的命令就在这个死循环之内执行。
1 #include<stdio.h>
2 #include<string.h>
3 #include<unistd.h>
4 #include<stdlib.h>
5 #include<sys/wait.h>
6 #define SIZE 100
7 #define NUM 26
8 int main()
9 {
10
11 char cmd[SIZE];
12 cmd[0]=0;
13 const char* cmd_line="[temp@VM-0-3-centos 13_lesson]# ";
14 while(1)
15 {
16 printf("%s",cmd_line);
}
首先需要从标准输入中获得字符串,这里选择了fgets方法,但需要注意的是当我们stdin的时候,会输入一个回车作为成功输入,这个fgets也会将回车读进去,所以需要找到回车的位置给他赋0。将输入的字符串保存在一个字符串数组里。
while(1)
{
printf("%s",cmd_line);
fgets(cmd,SIZE,stdin);
cmd[strlen(cmd)-1]='\0';
}
当我们输入命令可能会输入多个空格。所以使用strtok函数,用空格作为分隔符,将整个字符串,分割成一个个字符串,解析出来保存在一个指针数组当中(数组里面保存指针,指针指向一个字符串)
20 char* args[NUM];
21 args[0]=strtok(cmd," ");
22 int i=1;
23 do{
24 args[i]=strtok(NULL," ");
25 if(args[i]==NULL)
26 {
27 break;
28 }
29 i++;
30 }while(1);
这个场景很适合用多进程,fork创建一个子进程,让子进程去执行ls命令,执行一次后父进程将其回收,经过循环又一次接收命令,交给子进程去执行。
子进程怎么去执行呢,可以使用exec系列函数家族(去调用系统调用execve)使用识别出来的命令替换子进程去运行。
31 pid_t id=fork();
32 if(id<0)
33 {
34 perror("fork error");
35 continue;
36 }
37 else if(id==0)
38 {
39 execvp(args[0],args);
40 exit(1);
41 }
42 else{
43 int st=0;
44 waitpid(id,&st,0);
45 int exit_code=st>>8 & 0xff;
46 printf("exit code:%d\n",exit_code);
47
48 }
49 }
50
51 return 0;
52 }
同时也可以使用waitpid,通过st的高八位来查看是否进程替换成功。
我们编写的shell其实也是一个进程,在我们打开x-shell时,启动的时候先会进行身份检查,然后就会加载一个bash来使用命令行。
但是我们的shell只能执行简单的命令,稍微复杂的管道,重定向等就不适用了。