【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
个字符或者读完 - 读完以后末尾会加
- 从