【Linux】自定义shell的编写
📝前言:
这篇文章我们来讲讲==【Linux】简单自定义shell的编写==,通过这个简单的模拟实现,进一步感受shell的工作原理。
🎬个人简介:努力学习ing
📋个人专栏:Linux
🎀CSDN主页 愚润求学
🌄其他专栏:C++学习笔记,C语言入门基础,python入门基础,C++刷题专栏
目录
- 一,要实现的基本功能
- 二,打印命令行提示符
- (1)获取环境变量
- 对应接口 / 函数用法
- 实现
- (2)格式化打印提示符
- 对应接口 / 函数用法
- 实现
- 三,读取用户命令
- 对应接口 / 函数用法
- 实现
- 四,分析命令
- 用到的全局变量
- 对应接口 / 函数用法
- 实现
- 五,处理命令
- 对应接口 / 函数用法
- 实现
- 六,内建命令
- (1)cd
- 全局变量
- 对应接口 / 函数用法
- 实现
- (2)echo
- 实现
- (3)判断内建并调用
- 七,模拟导入环境变量
- 全局变量
- 对应接口 / 函数用法
- 实现
- 八,完整实现代码
一,要实现的基本功能
- 打印命令行提示符
- 读取用户输入命令
- 分析命令,得到命令行参数表
- 处理内建命令
- 处理命令
以及补充的:
- 加载环境变量和 更新环境变量(在
cd后更新环境变量)
下面我们分别对这些功能的实现进行讲解
二,打印命令行提示符
先看系统的shell的命令行提示符

格式:USERNAME@主机名:工作路径$
为了区分,我们计划实现的格式为:USERNAME@主机名:工作路径#
(1)获取环境变量
我们可以通过getenv来获取环境变量一下是对应关系
USERNAME:环境变量USER工作路径:环境变量PWD主机名:环境变量HOSTNAME(但是我的电脑上getenv(HOSTNAME)拿不到,所以我用库函数:gethostname)
对应接口 / 函数用法
- getenv:
- 头文件:
- 用法:
getenv(变量名) - 返回值:
- 成功:对应的字符串指针
- 失败:
NULL
- 头文件:
- gethostname:
- 头文件:
- 用法:
gethostname(char *name, size_t len)name:字符指针,指向用来存储获取到的hostname的缓冲区(这缓冲区就是代指一篇空间)len:表示name的大小
- 返回
- 成功:
0 - 失败:
1
- 成功:
- 头文件:
实现
31 const char* GetName()
32 {
33 char* user = getenv("USER");
34 return user == NULL? "None" : user;
35 }
36
37 const char* GetPwd()
38 {
39 // 因为在我们 chdir 改变工作路径以后,shell先获取变化,然后才会更新环境变量
40 char* pwd = getenv("PWD");
41 return pwd == NULL? "None" : pwd;
42 }
43
44 const char* GetHost() {
45 static char hostname[128]; // 这个要设置成全局的,不然不能返回cosnt
46 if (gethostname(hostname, sizeof(hostname)) == 0) {
47 return hostname;
48 }
49 return "None";
50 }
51
52 const char* GetHome()
53 {
54 char* home = getenv("HOME");
55 return home == NULL? "None" : home;
56 }
(2)格式化打印提示符
这里我们用到snprintf,将格式化的数据写入字符串缓冲区。
对应接口 / 函数用法
memset(用来给指定内存设置值):
- 头文件:
- 用法:
void *memset(void *s, int c, size_t n)s:要操作的内存块的指针c:要设置的值n:要设置的字节数
snprintf:
- 头文件:
- 用法:
int snprintf(char *str, size_t size, const char *format, ...);str:指向字符串缓冲区size:缓冲区的大小format:格式化字符串,就像printf里面的格式化一样
实现
58 void PrintCommandPrompt()
59 {
60 char Prompt[128];
61 memset(Prompt, 0, sizeof(Prompt));
62 snprintf(Prompt, sizeof(Prompt), "%s@%s:%s# ", GetName(), GetHost(), GetPwd());
63 printf("%s", Prompt);
64 }
三,读取用户命令
先看系统的:

我们输入ls -a -l的本质是,把它当做了一个长字符串"ls -a -l"
对应接口 / 函数用法
fgets:
- 头文件:
- 用法:
char *fgets(char *str, int size, FILE *stream);- 从
stream流里面读一行数据到str,遇到空格和不会停止,直到读取完size - 1个字符或者读完才停止。 - 读完以后末尾会加
- 从

