前言
所谓Shell,其实只干了两件事:监听和执行命令。
详细的代码参见我的Github库。
监听
Shell是这样一个软件,持续监听用户的输入,然后处理用户输入的指令,执行相应的功能。
基本上,所有的软件都是由一个死循环构成的,在这个死循环中,不断地监听、执行,重复这样一个过程。
我们Shell的基本框架是:
int main(int argc, char **argv) {
// 给定一个缓冲区,存储命令
char* command = (char*)malloc(BUFFER_SIZE * sizeof(char));
while(1) {
printf("ToyShell> ");
// 读取输入
int status = ReadLine(command);
// 判断输入
if(status > 0) {
char** token_list = ProcessLine(command);
ExecuteCommand(token_list);
} else if(status == INPUT_EOF) {
printf("Exit!\n");
break;
} else if(status == ERR_EXPR_TOO_LONG) {
FlushStdin();
}
}
free(command);
return 0;
}执行命令
命令的执行通常依靠两个函数:fork和exec,前者创建一个子进程,在这个子进程中执行命令,后者执行这个命令,具体的实现如下:
int ExecuteCommand(char **token_list) {
pid_t command_pid;
int status = 0;
// 处理输入
if(token_list[0] == NULL) {
return SUCCESS;
} else {if(strcmp(token_list[0], "cd") == 0) {
return Command_cd(token_list);
} else if(strcmp(token_list[0], "exit") == 0) {
return Command_exit(token_list);
}
}
// 创建子进程
command_pid = fork();
// 执行命令,并设置子进程/主进程的表现
if(command_pid == 0) {
if(execvp(token_list[0], token_list) == -1) {
perror("Execute Error");
exit(0);
return ERR_FAILED_TO_EXEC;
}
} else if(command_pid > 0) {
wait(&status);
} else {
perror("Fork Error");
exit(0);
}
free(token_list);
return SUCCESS;
}后记
在这个基础上,可以编写一些内置的命令。