首页 > 运维 > linux运维 > 正文

初识Linux · 自主Shell编写

雪夜
发布: 2025-06-19 16:27:03
原创
358人浏览过

本文介绍了自主shell编写的过程,模拟实现了bash解释器,并详细讲解了所需的预备知识,如进程的多方面知识。接下来,我们将直接进入shell编写部分。

1 命令行解释器部分

初识Linux · 自主Shell编写

我们在Centos版本下进行演示,通常看到的命令行解释器显示为当前用户名(如_lazy)、主机名(如VM-12-14-centos)和当前目录(如~)。我们的目标是复制一个类似的命令行解释器。

首先,如何获取用户名、主机名和当前目录?我们可以通过环境变量来获取这些信息。

初识Linux · 自主Shell编写初识Linux · 自主Shell编写初识Linux · 自主Shell编写

在环境变量表中,我们可以看到HOSTNAME、PWD和USER分别代表主机名、当前路径和当前用户名。我们可以通过三种方式获取这些变量:environ、命令行参数表和getenv。我们选择使用getenv来获取这些信息:

char* argv[] = {
    getenv("HOSTNAME"),
    getenv("USER"),
    getenv("PWD")
};
登录后复制

将获取到的环境变量放在数组argv中,然后进行打印。我们使用printf来打印数组的三个元素,但由于命令行参数是在后面输入的,我们不能使用\n作为结束符。相反,我们使用snprintf函数来将所有输出放入一个字符串中,这样更容易控制输出。如果你的man手册配置不全,可以使用以下命令:

初识Linux · 自主Shell编写初识Linux · 自主Shell编写

因此,第一部分的临时代码如下:

void OutputBash()
{
    char line[SIZE];
<pre class="brush:php;toolbar:false">char* username = GetUser();
char* hostname = Gethost();
char* cwd = Getcwd();

snprintf(line, sizeof(line), "[%s@%s %s]> ", username, hostname, cwd);
printf("%s", line);
fflush(stdout);

// char* argv[] = {
//     getenv("HOSTNAME"),
//     getenv("USER"),
//     getenv("PWD")
// };
// char* line;
// //printf("[%s@%s %s]>", argv[0], argv[1], argv[2]);
// fflush(stdout);
登录后复制

}

相关函数的定义如下:

#define SIZE 512</p><p>char<em> GetUser()
{
char</em> user = getenv("USER");
if(user == NULL) return NULL;
return user;
}</p><p>char<em> Gethost()
{
char</em> host = getenv("HOSTNAME");
if(host == NULL) return NULL;
return host;
}</p><p>char<em> Getcwd()
{
char</em> cwd = getenv("PWD");
if(cwd == NULL) return NULL;
return cwd;
}
登录后复制

但这只是临时的,因为我们的pwd显示不完善:

初识Linux · 自主Shell编写

目前显示的并不是最完善的,应该只显示当前目录。我们可以通过分割字符串来解决这个问题,使用指针指向最后一个/,但不建议使用函数,因为需要二级指针。我们可以使用宏来实现:

初识Linux · 自主Shell编写

我们可以使用以下方法操作:

初识Linux · 自主Shell编写

这样,较为完善的命令行解释器部分就完成了。

2 获取用户命令行参数

我们已经解决了第一个问题,现在需要获取用户的命令行参数。在获取用户命令行参数时,我们应该使用什么函数呢?可以使用scanf吗?如果使用scanf,输入ls -l -n -a时,只能获取到ls,因为scanf是通过空格或换行符来获取的。因此,我们推荐使用fgets或gets,但由于后面有文件IO操作,我们选择使用fgets作为缓冲:

int GetUserCommand(char<em> usercommand, size_t n)
{
char</em> s = fgets(usercommand, n, stdin);
if(s == NULL) return -1;</p><pre class="brush:php;toolbar:false">return strlen(s);
登录后复制

}

但此代码存在一些缺陷,详见第4部分。

3 命令行参数进行分割

获取命令后,不能带空格执行,因此我们需要使用函数将命令行参数分割。我们使用C语言的库函数strtok来进行分割:

初识Linux · 自主Shell编写

第一个参数是待分割的字符串,第二个参数是分割符。第一次分割后,将第一个参数置为NULL以继续分割。我们将分割后的字符串放入数组中,方便后面的进程替换工作。我们定义一个全局变量来存储分割后的字符串:

#define SEP " "
char<em> gArgv[SIZE];
登录后复制

需要注意的是,使用单引号的空格与strtok不匹配,因为这只是一个字符,不是const char。

void SplitCommand(char* usercommand)
{
gArgv[0] = strtok(usercommand, SEP);
int index = 1;
while((gArgv[index++] = strtok(NULL, SEP)));//分割之后函数返回NULL 恰好作为结尾
}
登录后复制

分割后的函数返回NULL,可以作为数组的结束标志。

4 执行命令

现在我们可以直接执行命令了,至少目前可以执行简单的命令。我们需要涉及进程程序替换,因为分割好的命令已经放在了全局变量中,我们可以直接创建函数:

void ExcuteCommand()
{
pid_t id = fork();</p><pre class="brush:php;toolbar:false">if(id < 0)
{
    perror("fork error");
    return;
}
else if(id == 0)
{
    execvp(gArgv[0], gArgv);
    perror("execvp error");
    exit(-1);
}
else
{
    int status;
    waitpid(id, &status, 0);
    int lastcode = WEXITSTATUS(status);
    if(lastcode != 0) printf("%s:%s:%d\n", gArgv[0], strerror(lastcode), lastcode);
}
登录后复制

}

这些代码是进程替换时介绍过的,我们只需进行一些修饰,使代码更美观。然而,执行时仍会遇到问题,因为命令行输入时会自动输入回车,导致无法执行。我们需要去掉回车:

初识Linux · 自主Shell编写

使用宏定义ZERO来解决这个问题。

5 判断命令是否为内建命令

如果我们执行的是echo、cd等内建命令,只能由父进程执行,我们不能创建子进程。我们需要判断是否为内建命令,如果是,则由父进程执行,并跳过下一步。我们可以通过strcmp来判断内建命令:

void Cd()
{
const char *path = gArgv[1];
if(path == NULL) path = Gethost();
// path 一定存在
chdir(path);</p><pre class="brush:php;toolbar:false">// 刷新环境变量
char temp[SIZE*2];
getcwd(temp, sizeof(temp));
snprintf(cwd, sizeof(cwd), "PWD=%s", temp);
putenv(cwd); // OK
登录后复制

}

int IsInorder() { int yes = 0; const char *enter_cmd = gArgv[0]; if(strcmp(enter_cmd, "cd") == 0) { yes = 1; Cd(); } else if(strcmp(enter_cmd, "echo") == 0 && strcmp(gArgv[1], "$?") == 0) { yes = 1; printf("%d\n", lastcode); lastcode = 0; } return yes; }

以cd为例,判断cd是内建命令后,在cd函数中实现。我们使用chdir函数改变当前工作目录,之后更新环境变量中的PATH。此时,自主Shell编写工作基本完成。

感谢阅读!

以上就是初识Linux · 自主Shell编写的详细内容,更多请关注php中文网其它相关文章!

最佳 Windows 性能的顶级免费优化软件
最佳 Windows 性能的顶级免费优化软件

每个人都需要一台速度更快、更稳定的 PC。随着时间的推移,垃圾文件、旧注册表数据和不必要的后台进程会占用资源并降低性能。幸运的是,许多工具可以让 Windows 保持平稳运行。

下载
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系admin@php.cn
最新问题
开源免费商场系统广告
热门教程
更多>
最新下载
更多>
网站特效
网站源码
网站素材
前端模板
关于我们 免责申明 意见反馈 讲师合作 广告合作 最新更新
php中文网:公益在线php培训,帮助PHP学习者快速成长!
关注服务号 技术交流群
PHP中文网订阅号
每天精选资源文章推送
PHP中文网APP
随时随地碎片化学习
PHP中文网抖音号
发现有趣的

Copyright 2014-2025 https://www.php.cn/ All Rights Reserved | php.cn | 湘ICP备2023035733号