前言
所谓Shell,其实只干了两件事:监听和执行命令。
详细的代码参见我的Github库。
监听
Shell是这样一个软件,持续监听用户的输入,然后处理用户输入的指令,执行相应的功能。
基本上,所有的软件都是由一个死循环构成的,在这个死循环中,不断地监听、执行,重复这样一个过程。
我们Shell的基本框架是:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21
| 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
,前者创建一个子进程,在这个子进程中执行命令,后者执行这个命令,具体的实现如下:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30
| 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; }
|
后记
在这个基础上,可以编写一些内置的命令。