14.C 语言实现一个迷你 Shell
文章目录
- 项目名称:用 C 语言实现一个迷你 Shell
- 一、项目简介
- 二、完成的功能
- 三、代码部分
- 四、程序运行流程
- 五、用到的知识点解析
项目名称:用 C 语言实现一个迷你 Shell
一、项目简介
本项目是一个用 C 语言编写的简易命令行解释器(Shell),支持用户输入命令、解析参数、创建子进程执行命令,并阻塞等待子进程结束。它模拟了 Linux 下 Bash 的基本行为,适合初学者练习进程控制和字符串处理。
二、完成的功能
- 显示提示符(包含当前路径)
- 读取用户输入
- 使用
strtok()
解析命令参数 - 使用
fork()
创建子进程 - 使用
execvp()
执行命令 - 使用
waitpid()
阻塞等待子进程结束 - 支持
exit
命令退出 Shell
三、代码部分
#include <stdio.h>
#include <stdlib.h>
#include <assert.h>
#include <string.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/wait.h>#define PWD "PWD" // 环境变量名,用于获取当前路径
#define LINE_NUM 1024 // 命令最大长度
#define OPT_NUM 64 // 参数最大个数char lineCommand[LINE_NUM]; // 这里所存放的是已经提取完成的
char* myargv[OPT_NUM]; // 存放分割后的参数指针数组// 执行进程程序替换使用 execvp
void do_exec(char** myargv_)
{pid_t id = fork(); // 创建子进程assert(id >= 0); // 保证 fork 成功if (id == 0){// 执行进程程序替换使用 execvpexecvp(myargv_[0], myargv_);perror("execvp failed"); // 如果 execvp 失败,打印错误信息exit(1); // 子进程退出}// 父进程等待子进程结束,这里我就直接选用阻塞式等待int status;pid_t ret = waitpid(id, &status, 0);printf("child id:%d, sig code:%d, exit code:%d\n", ret, status & 0x7F, (status >> 8) & 0xFF);
}// 完成字符串切割,这里调用 strtok
char** do_prase(char* buff)
{int i = 0;char* token = strtok(buff, " ");while (token != NULL){myargv[i++] = token;token = strtok(NULL, " "); // 这表示从上一次分割的位置开始继续进行分割}myargv[i] = NULL; // 最后一个参数设为 NULL,方便 execvp 使用return myargv;
}// 这里就会像 bash 一样输出行信息还有当前路径
int do_face()
{printf("zy@Cent %s:", getenv(PWD));fflush(stdout);// 获取用户输入char* s = fgets(lineCommand, sizeof(lineCommand) - 1, stdin);assert(s != NULL);(void)s;// 清除最后一个 \nlineCommand[strlen(lineCommand) - 1] = '\0';// 支持 exit 命令退出 shellif (strcmp(lineCommand, "exit") == 0)return -1;// 这里加入了断言,再输入不为空的情况去进行字符串的剪切和存储// 剪切完成后得到的就是一个指针数组,再返回这个数组的地址,所以我这里的返回值就必须是二级指针do_prase(lineCommand);return 0;
}// 这里写一个死循环可以去持续读取执行指令
int main()
{while (1){// 1、对指令进行分割提取if (do_face() < 0)break;// 2、调用进程替换进行执行,然后父进程等待do_exec(myargv);}return 0;
}
四、程序运行流程
- 显示提示符(当前路径)
- 读取用户输入
- 判断是否输入
exit
,是则退出 - 使用
strtok()
分割命令参数 - 创建子进程并执行命令
- 父进程等待子进程结束
- 回到第 1 步,继续循环
五、用到的知识点解析
技术点 | 说明 |
---|---|
fgets() | 安全读取用户输入 |
strtok() | 字符串切割,提取命令参数 |
fork() | 创建子进程 |
execvp() | 执行命令,自动搜索路径 |
waitpid() | 阻塞等待子进程结束 |
exit 命令 | 通过字符串判断实现退出功能 |