当前位置: 首页 > news >正文

横山专业做网站建设的公司广州越秀区房价多少钱一平方

横山专业做网站建设的公司,广州越秀区房价多少钱一平方,岳麓做网站的公司,工商网查询营业执照个人主页:C忠实粉丝 欢迎 点赞👍 收藏✨ 留言✉ 加关注💓本文由 C忠实粉丝 原创 Linux基础-shell的简单实现 收录于专栏[Linux学习] 本专栏旨在分享学习Linux的一点学习笔记,欢迎大家在评论区交流讨论💌 目录 1, 全局变…

个人主页:C++忠实粉丝
欢迎 点赞👍 收藏✨ 留言✉ 加关注💓本文由 C++忠实粉丝 原创

Linux基础-shell的简单实现

收录于专栏[Linux学习]
本专栏旨在分享学习Linux的一点学习笔记,欢迎大家在评论区交流讨论💌

目录

1, 全局变量和常量定义

2. 环境信息获取

2.1 GetUserName

2.2 GetHostName

2.3 GetPwd

2.4 LastDir

3. 命令行提示符

3.1 MakeCommandLine

3.2  PrintCommandLine

4, 命令输入处理

4.1 GetCommandLine

4.2 ParseCommandLine

5. 命令调试

5.1 debug

6. 命令执行

6.1 ExecuteCommand

子进程执行命令:

等待子进程结束:

处理子进程的返回状态: 

7. 环境变量管理

7.1 AddEnv

 7.2 InitEnv

8. 内建命令处理

8.1 CheckAndExeBuiltCommand

8.1.1 cd命令

8.1.2 export命令

8.1.3 evn命令

8.1.4 echo命令 

8.2 为什么使用内建命令 

9. 主函数

10. 效果展示:


1, 全局变量和常量定义

功能 : 定义常量和全局变量,包括命令行参数、环境变量、当前工作目录、和最近的命令执行状态代码。

#include <iostream>
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <string>
#include <unistd.h>
#include <sys/types.h>
#include <sys/wait.h>using namespace std;const int basesize = 1024;
const int argvnum = 64;
const int envnum = 64;//全局的命令行参数
char *gragv[argvnum];
int gargc = 0;//全局变量
int lastcode = 0;//我的系统的环境变量
char *genv[envnum];//全局的当前shell工作路径
char pwd[basesize];
char pwdenv[basesize];

basesize: 定义了缓冲区的基础大小,用于存储用户输入的命令和路径。

argvnum: 定义最大命令行参数的数量。

envnum: 定义最大环境变量的数量。

gargv: 存储解析后的命令行参数的数组。

gargc: 表示当前解析出的参数数量。

lastcode: 保存最近执行命令的退出状态。

genv: 存储环境变量的数组。

pwd 和 pwdenv: 存储当前工作目录和环境变量PWD的缓冲区。

2. 环境信息获取

功能 : 获取当前用户、主机名和当前工作目录的信息,返回相应的字符串。

2.1 GetUserName

GetUserName: 获取当前用户的用户名,使用getenv从环境变量中获取,若未获取到,则返回"None"。 

string GetUserName()
{string name = getenv("USER");return name.empty() ? "None" : name;
}

2.2 GetHostName

GetHostName: 获取主机名,类似于获取用户名的方式。 

string GetHostName()
{string hostname = getenv("HOSTNAME");return hostname.empty() ? "None" : hostname;
}

2.3 GetPwd

GetPwd: 获取当前工作目录,使用getcwd函数获取并更新环境变量PWD。如果获取失败,返回"None"。

string GetPwd()
{if (nullptr == getcwd(pwd, sizeof(pwd)))return "None";snprintf(pwdenv, sizeof(pwdenv), "PWD=%s", pwd);putenv(pwdenv);return pwd;
}

补充知识:

snprintf 是一个安全的字符串格式化函数,用于将格式化的数据写入字符串。

pwdenv 是另一个字符数组,用于存储更新后的环境变量字符串。

这里,"PWD=%s" 是格式化字符串,%s 被当前工作目录的值(即 pwd 中的值)替换。最终结果类似于 PWD=/home/user(假设当前工作目录是 /home/user)。

putenv 是一个函数,用于设置环境变量。

通过调用 putenv(pwdenv),将之前构造的环境变量字符串 PWD=/path/to/current/dir 添加到进程的环境中。

注意,使用 putenv 要确保 pwdenv 的内容在后续使用中依然有效,因为 putenv 不会复制传入的字符串。

2.4 LastDir

LastDir: 从当前路径中提取最后一个目录名称,方便在命令行提示符中显示。 

string LastDir()
{string curr = GetPwd();if (curr == "/" || curr == "None")return curr;size_t pos = curr.rfind("/");if (pos == std::string::npos)return curr;return curr.substr(pos + 1);
}

注意 : 这里curr == "/" || curr == "None" 我们都不需要额外处理, 直接返回就行, 因为curr为"/" 表示根目录, 为None时, 我们直接返会空就行 

3. 命令行提示符

功能:生成和打印命令行提示符,包含用户、主机和当前目录信息。 

3.1 MakeCommandLine

MakeCommandLine: 生成当前命令行提示符的字符串格式,包括用户、主机和当前目录。

string MakeCommandLine()
{//[XXX@XXXXX myshell]$ 这里就与普通命令行进行区分char command_line[basesize];snprintf(command_line, basesize, "[%s@%s %s]#", GetUserName().c_str(), GetHostName().c_str(), LastDir().c_str());return command_line;
}

3.2  PrintCommandLine

PrintCommandLine: 打印生成的命令行提示符到标准输出。 

void PrintCommandLine()
{printf("%s", MakeCommandLine().c_str());fflush(stdout);
}

4, 命令输入处理

功能:从标准输入获取用户输入的命令,并解析成命令及其参数。 

4.1 GetCommandLine

GetCommandLine: 从标准输入获取用户的命令行输入,使用fgets读取并处理换行符。

bool GetCommandLine(char command_buffer[], int size)
{//我们认为 : 我们要将用户出入的命令行 -> 当作一个完整的字符串//"ls -a -1 -n"char* result = fgets(command_buffer, size, stdin);if(!result){return false;}command_buffer[strlen(command_buffer) - 1] = 0;if(strlen(command_buffer) == 0) return false;return true;
}

补充知识:

fgets 是一个标准库函数,用于从标准输入(stdin)读取一行字符,最多读取 size - 1 个字符,并将其存储在 command_buffer 中。

fgets 会在读取到换行符 ('\n') 或 EOF(文件结束符)时停止读取,并会在 command_buffer 的末尾自动添加一个空字符 ('\0')。

如果成功读取,result 将指向 command_buffer;如果失败(例如,输入错误或 EOF),result 将为 nullptr。

注意:  strlen(command_buffer) - 1 获取字符串的最后一个字符(换行符)的索引,并将其设为 0,以去掉换行符。

比如:我们输入 ls -a -l -n

fgets 会将缓冲区填充为: command_buffer = "ls -a -l -n\n\0"

经过strlen(command_buffer) - 1处理后 : "ls -a -l -n\0"

4.2 ParseCommandLine

ParseCommandLine: 使用strtok将输入的命令行字符串分割为单独的命令和参数,并存储在gargv数组中。

void ParseCommandLine(char command_buffer[], int len)
{(void)len;memset(gargv, 0, sizeof(gargv));gargc = 0;//"ls -a -l -n"const char *sep = " ";gargv[gargc++] = strtok(command_buffer, sep);//=是刻意写的while((bool)(gargv[gargc++] = strtok(nullptr, sep)));gargc--;
}

补充知识:

 strtok 函数会将 command_buffer 字符串中的第一个分隔符(空格)替换为 \0,并返回指向第一个标记的指针,存储到 gargv 数组中。

strtok(nullptr, sep) 意味着继续解析之前传入的字符串。

注意 (bool) 转换是为了确保表达式的结果为布尔值,这样可以明确表示循环的条件。

5. 命令调试

5.1 debug

功能 : 输出当前命令参数的数量和每个参数的值,以帮助开发和调试。 

void debug()
{printf("argc: %d\n", gargc);for(int i = 0; gargv[i]; i++){printf("argv[%d]: %s\n", i, gargv[i]);}
}

6. 命令执行

6.1 ExecuteCommand

功能:通过fork()和execvpe()创建子进程执行用户命令,并等待其完成。 

bool ExecuteCommand()
{//让子进程进行执行pid_t id = fork();if(id < 0) return false;if(id == 0){//子进程//1. 执行命令execvpe(gargv[0], gargv, genv);//2. 退出exit(1);}int status = 0;pid_t rid = waitpid(id, &status, 0);if(rid > 0){if(WIFEXITED(status)){lastcode = WEXITSTATUS(status);}else{lastcode = 100;}return true;}return false;
}

子进程执行命令:

execvpe(gargv[0], gargv, genv);execvpe 用于执行指定的命令。它会用新的程序替换当前进程(子进程)。参数说明:

gargv[0]:命令的名称(通常是命令的路径)。

gargv:一个字符串数组,包含传递给命令的参数。

genv:一个字符串数组,包含环境变量。

如果 execvpe 成功,当前进程(子进程)将被新的程序替换,之后的代码将不会执行。

如果 execvpe 失败(例如命令未找到),子进程将执行 exit(1),返回状态 1,以指示错误。

等待子进程结束:

int status = 0;:用于存储子进程的退出状态。

waitpid(id, &status, 0):在父进程中调用,等待指定的子进程(由 id 指定)结束。结果存储在 status 变量中。

返回值 rid:如果成功,返回已结束子进程的 PID;如果失败,返回 -1。

处理子进程的返回状态: 

if(rid > 0):确认 waitpid 调用成功,rid 应该是大于 0 的子进程 PID。

WIFEXITED(status):这个宏检查子进程是否正常退出(通过 exit() 或 return 语句)。

WEXITSTATUS(status):如果子进程正常退出,获取其返回状态并将其存储在 lastcode 中。

如果子进程未正常退出(例如由于信号导致的终止),则将 lastcode 设置为 100,这通常用于指示异常情况。

return true;:表示成功执行命令并处理了其退出状态。

7. 环境变量管理

功能:动态分配内存,将新的环境变量添加到genv数组中。

7.1 AddEnv

void AddEnv(const char* item)
{int index = 0;while(genv[index]){index++;}genv[index] = (char*)malloc(strlen(item) + 1);strncpy(genv[index], item, strlen(item) + 1);genv[++index] = nullptr;
}

功能 : 添加环境变量:该函数接受一个字符串 item 作为参数,并将其添加到 genv 环境变量数组中。

逐行分析

int index = 0;:初始化索引为 0,用于遍历 genv 数组。

while(genv[index]):遍历 genv 数组,直到找到第一个空指针,表示可以插入新环境变量的位置。

genv[index] = (char*)malloc(strlen(item) + 1);:

为新的环境变量分配内存。malloc 分配的内存大小为 item 字符串的长度加 1(为字符串结束符 \0 留出空间)。

strncpy(genv[index], item, strlen(item) + 1);:

将 item 的内容复制到 genv[index] 中。使用 strncpy 复制到长度 strlen(item) + 1,确保包含字符串结束符。

genv[++index] = nullptr;:

在数组中下一个位置设置为 nullptr,标志着环境变量的结束。

 7.2 InitEnv

void InitEnv()
{extern char **environ;int index = 0;while(environ[index]){genv[index] = (char*)malloc(strlen(environ[index] + 1));strncpy(genv[index], environ[index], strlen(environ[index] + 1));index++;}genv[index] = nullptr;
}

功能 : 初始化环境变量:该函数从系统环境变量中读取所有环境变量并将其存储在 genv 数组中。

逐行分析

extern char **environ;:声明外部变量 environ,这是一个指向环境变量字符串数组的指针

int index = 0;:初始化索引为 0,用于遍历 environ。

while(environ[index]):遍历 environ 数组,直到找到第一个空指针,表示所有环境变量都已读取。

genv[index] = (char*)malloc(strlen(environ[index]) + 1);:

为每个环境变量分配内存。这里 strlen(environ[index]) 计算字符串的长度,并加 1 来包含 \0 结束符。

strncpy(genv[index], environ[index], strlen(environ[index] + 1));:

将 environ[index] 的内容复制到 genv[index] 中。这里同样存在一个错误,应该是 strncpy(genv[index], environ[index], strlen(environ[index]) + 1);。

index++;:增加索引,以便处理下一个环境变量。

genv[index] = nullptr;:在数组最后设置 nullptr,表示环境变量的结束

8. 内建命令处理

8.1 CheckAndExeBuiltCommand

bool CheckAndExeBuiltCommand()
{if(strcmp(gargv[0], "cd") == 0){//内建命令if(gargc == 2){chdir(gargv[1]);lastcode = 0;}else{lastcode = 1;}return true;}else if(strcmp(gargv[0], "export") == 0){//export也是内建命令if(gargc == 2){AddEnv(gargv[1]);lastcode = 0;}else{lastcode = 2;}return true;}else if(strcmp(gargv[0], "env") == 0){for(int i = 0; genv[i]; i++){printf("%d\n", genv[i]);}lastcode = 0;return true;}else if(strcmp(gargv[0], "echo") == 0){if(gargc == 2){//echo $?//echo $PATH//echo helloif(gargv[1][0] == '$'){if(gargv[1][1] == '?'){printf("%d\n", lastcode);lastcode = 0;}else{printf("%s\n", gargv[1]);lastcode = 0;}}else{lastcode = 3;}return true;}return false;}
}

8.1.1 cd命令

功能:用于更改当前工作目录。

逻辑:

检查参数个数 gargc 是否等于 2(即命令和目录)。

如果参数正确,调用 chdir 函数改变目录,并将 lastcode 设置为 0,表示成功。

如果参数不正确,将 lastcode 设置为 1,表示错误。

chdir() : 将调用进程的当前工作目录更改为path中指定的目录 

8.1.2 export命令

功能:用于设置或导出环境变量。

逻辑:

同样检查参数个数 gargc 是否为 2。

如果正确,调用 AddEnv 函数添加环境变量,并将 lastcode 设置为 0。

如果参数不正确,设置 lastcode 为 2。

8.1.3 evn命令

功能:列出所有环境变量。

逻辑:

遍历 genv 数组,打印每个环境变量。

将 lastcode 设置为 0。

8.1.4 echo命令 

功能:输出字符串或变量。

逻辑:

检查参数个数是否为 2。

如果是,检查 gargv[1] 的第一个字符是否为 $:

如果是 $?,输出 lastcode 的值。

如果是其他以 $ 开头的字符串,直接输出这个字符串(假设它是环境变量)。

如果没有 $,则将 lastcode 设置为 3。

如果参数个数不正确,返回 false。

8.2 为什么使用内建命令 

快速响应:内建命令通常直接在 shell 进程内执行,无需创建新的进程,减少了上下文切换的开销。这使得内建命令的执行速度更快。

基本功能:内建命令提供了一些与 shell 紧密相关的基本功能,如改变目录(cd)、设置环境变量(export)、获取当前环境(env)等,这些操作通常与 shell 的状态直接相关。

环境影响:某些内建命令(如 cd)会影响 shell 的状态(例如当前工作目录),如果用外部程序实现,改变的状态不会反映到 shell 中。

简化用户操作:用户可以直接使用内建命令而无需担心路径问题。例如,cd 命令只需要提供目标路径,而不必寻找相应的外部可执行文件。

状态保持:内建命令如 echo 和 export 能够直接访问 shell 的状态和环境变量,而不需要通过外部程序来管理,这样可以更好地处理如 $?(上一个命令的退出状态)这样的特殊情况。

9. 主函数

 功能:主程序循环,负责显示提示符、获取用户命令、解析命令、检查内建命令,并执行命令。

int main()
{InitEnv();char command_buffer[basesize];while(true){//1. 命令行提示符PrintCommandLine();//command_buffer -> output//2. 获取用户命令if(!GetCommandLine(command_buffer, basesize)){continue;}//3. 解析命令ParseCommandLine(command_buffer, strlen(command_buffer));if(CheckAndExeBuiltCommand()){continue;}4. 执行命令ExecuteCommand();}return 0;
}

10. 效果展示:

http://www.yayakq.cn/news/137056/

相关文章:

  • 展示网站多少钱一个大型集团网站
  • 广东公布最新传染了东营网站建设优化
  • 开个做网站公司wordpress全文检索
  • 网站建设云南苏州有什么好玩的景点
  • 做网站刷流量挣钱吗网站模板建站教程视频教程
  • win10可以自己做网站wordpress微信登录
  • 郑州app开发多少钱公众号排名优化软件
  • 移动wap站点营销网站设计公司排名
  • 六安市裕安区建设局网站wordpress自动分表
  • 免费大型网站网站权限配置
  • 做电影资源缓存网站教程菏泽网站建设哪好
  • 高端网站定制设计公司海珠区手机版网站建设
  • wordperss网站做负载均衡制作高端app开发公司
  • 广元网站建设优化多语言商城网站开发
  • 衡水网站建设制作网站托管要求
  • 中华建设杂志社网站灰色词排名接单
  • 网站建设客户需求表 文库手机网站效果图做多大的
  • 数据来源于网站需如何做脚注做网站基本东西
  • 成都网站关键词商城类网站开发
  • 唐河企业网站制作哪家好wordpress seo主题
  • 西安保洁公司网站建设重庆建工集团股份有限公司官网
  • 南昌net网站开发湖北智能网站建设推荐
  • 手把手教你搭建自己的网站深圳网站设计价格表
  • jeecg 3.7 网站开发苏州集团网站制作设计
  • 网站品牌推广策略网站建设代理
  • 小学网站建设方案书wordpress负载状态100%
  • 青岛哪家网站建设好wordpress内页收录
  • 手机网站的引导页如何丰富网站内容
  • 网站怎么上传源码辽宁建设工程信息网诚信库怎么入库
  • 厦门机场到厦门厦门网站建设通化县建设局网站