Linux 自主 shell 编写(C 语言实现)

Linux 自主 shell 编写(C 语言实现)

  • 效果
  • 主要步骤
    • 打印命令行提示符
    • 获取用户命令字符串
    • 切割用户命令字符串
    • 执行命令
    • 循环
  • 至此源码(简易半成品)
  • 细节
    • 内建命令问题
      • cd
    • 退出码问题
    • echo 查看退出码
  • 完整源码
    • makefile
    • myshell.c

效果

效果嘛和 命令行解释器 一模一样,这里就不贴图了

只是把 # (超管)$ (普通用户) 符号改为 > 以作区分

注意哦: 删除键不能直接使用,要配合 ctrl 键才行

主要步骤

打印命令行提示符

在 Linux 终端(命令行)里,首先看到的是 命令行提示符

[exercise@localhost my_shell]$ 

shell 一旦跑起来,定是要先打印 命令行提示符 的,但是这玩意对于不同的用户是不一样的呀,所以不能单纯的打印出来,而是要获取用户名,主机名等等,如何获取?目前来说对各种 系统接口还不熟,那就直接使用 环境变量

命令行执行 env 命令,就可以看到很多 环境变量 ^ ^

系统环境变量 很多,不容易直接得到想要的,所以可以使用库函数 getenv 来获取,需要包含头文件 #include ,函数原型如下:

char *getenv(const char *name);

那么 用户名主机名工作目录 分别在 USERHOSTNAMEPWD 内,直接使用 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

你可能感兴趣的:(Linux,linux,c语言,服务器,运维)