C语言手写简单的Shell

前言

所谓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;
}

执行命令

命令的执行通常依靠两个函数:forkexec,前者创建一个子进程,在这个子进程中执行命令,后者执行这个命令,具体的实现如下:

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;
}

后记

在这个基础上,可以编写一些内置的命令。

文章作者:
文章链接: https://www.coderlock.site/2025/07/20/C语言手写简单的Shell/
版权声明: 本博客所有文章除特别声明外,均采用 CC BY-NC-SA 4.0 许可协议。转载请注明来自 寒夜雨