当我们打开一个终端的时候,我们可以在上面输入各种命令,从而与终端实现互动。
可以发现,每当一个指令的执行结束后,终端会等待我们的下一条指令的输入。
这就类似于我们写了一个死循环,一直在等待着命令的输入。当有一条指令输入时,创建子进程并将子进程替换为命令,执行子进程并且父进程等待子进程的执行结束,从而实现交互。
我们可以利用之前学的进程创建和进程替换来编写一个简单的自主shell。
要实现一个自主shell ,我们需要循环执行以下过程:
- 读取命令
- 解析命令
- 创建子进程
- 替换子进程
- 父进程等待子进程退出
实现:
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/wait.h>
#include <ctype.h>
int argc = 0;
char* argv[8] = {};
void do_parse(char* buf){ // 字符串解析
argc = 0;
int i = 0;
int status = 0;
for(; buf[i]!=0; i++){
if(!isspace(buf[i])&&status == 0){ //如果是字符并且是从空格到字符
argv[argc++] = buf + i;
status = 1;
}else if(isspace(buf[i])){ // 如果是字符到空格
buf[i] = 0;
status = 0;
}
}
}
void do_shell(){
pid_t pid = fork(); // 创建子进程
if(pid == -1){
perror("fork");
return;
}
else if(pid > 0)
wait(NULL); // 父进程等待子进程结束
else{ // 子进程进行进程替换
if(execvp(argv[0],argv) == -1)
perror("execvp"),exit(1);
}
}
int main(){
char buf[1024] = {};
while(1){
memset(buf, 0x00, sizeof(buf));
printf("shell >");
scanf("%[^\n]", buf); // 命令行读取
scanf("%*c");
if(strcmp(buf, "exit") == 0)
break;
do_parse(buf);
do_shell();
}
}
但是此时我们所编写的这个 shell 是不支持输出重定向,追加重定向和输入重定向功能的。