效果嘛和 命令行解释器 一模一样,这里就不贴图了
只是把 #
(超管) 或 $
(普通用户) 符号改为 >
以作区分
注意哦: 删除键不能直接使用,要配合 ctrl
键才行
在 Linux 终端(命令行)里,首先看到的是 命令行提示符 :
[exercise@localhost my_shell]$
此 shell
一旦跑起来,定是要先打印 命令行提示符 的,但是这玩意对于不同的用户是不一样的呀,所以不能单纯的打印出来,而是要获取用户名,主机名等等,如何获取?目前来说对各种 系统接口还不熟,那就直接使用 环境变量 嘛
命令行执行 env
命令,就可以看到很多 环境变量 ^ ^
但 系统环境变量 很多,不容易直接得到想要的,所以可以使用库函数 getenv
来获取,需要包含头文件 #include
,函数原型如下:
char *getenv(const char *name);
那么 用户名、 主机名 和 工作目录 分别在 USER
、HOSTNAME
和 PWD
内,直接使用 getenv
函数获取即可
最后使用 snprintf()
函数拼接成 命令行提示符 的格式即可,函数原型:
int snprintf(char *str, size_t size, const char *format, ...);
C 语言 获取键盘字符串 可以使用库函数 scanf()
,但它遇到空格可就不继续读取了,而它的高端玩法还不熟
咱就老老实实使用 fgets
函数,原型:
char *fgets(char *s, int size, FILE *stream);
这一步是必要的,因为日后一定是需要 进程替换 的,进程替换 就一定需要将用户命令以空格为分隔符打散分开,是库函数参数的原因,是刚需
如何实现呢?倒是也很简单,我们可以直接将空格替换为 '\0'
,那么一个长串就变为若干个子串
如果要执行用户输入的命令,是要创建子进程来完成的;那我们就需要为进程传递 命令行参数 来实现,毕竟不同的选项具有不同的功能,所以切割的字串分别放入 命令行参数表 argv[]
里即可,argv
的每一个元素都是一个指针,指向被切完成的子串(最后一个指针为 NULL
)
那么只需要将 argv
的第一个元素指向第一个子串,第二个元素指向第二个子串,以此类推
但这比较麻烦,咱可以使用库函数 strtok()
完成; 命令行参数表 也可以设置为全局的,好调用
获取用户的命令后,不执行等啥呢?
当然啦,执行命令不是自己当前进程来执行,而是 创建子进程,在利用 进程替换,此时子进程就可以执行你想要的全新的代码
一个 shell
怎么能只运行一条命令呢?所以我们需要将上述过程循环起来,这样就能无限制运行命令
至此,简易到不能再简易的 shell
就实现好了
#include
#include
#include
#include
#include
#include
#include
#define SIZE 512
#define ZERO '\0'
#define SEP " "
#define NUM 32
char* gArgv[NUM];
const char* getUserName()
{
const char* username = getenv("USER");
if (username == NULL) return "None";
return username;
}
const char* getHostName()
{
const char* hostname = getenv("HOSTNAME");
if (hostname == NULL) return "None";
return hostname;
}
// 临时
const char* getCwd()
{
const char* cwd = getenv("PWD");
if (cwd == NULL) return "None";
return cwd;
}
void MakeCommandLineAndPrint()
{
char line[SIZE];
const char* username = getUserName();
const char* hostname = getHostName();
const char* cwd = getCwd();
snprintf(line, sizeof(line), "[%s@%s %s]> ", username, hostname, cwd);
printf("%s", line);
fflush(stdout