linux之自主shell编写

news/发布时间2024/7/27 9:05:30

在这个shell编写中,我们遇到了很多我们之前很少使用的函数

1.getenv/putenv

     1.getenv

        头文件:#include<stdlib.h>

   函数原型: char * getenv(const char* name);

   函数说明:getenv()用来取得参数name环境变量的内容。

   函数参数:name为环境变量的名称,如果该变量存在则会返回指向该内容的指针。环境变量的格式为namevalue

  返回值:若环境变量存在,返回环境变量值的指针,否则返回NULL

     2.putenv

        头文件:#include<stdlib.h>

  函数原型: int putenv(const char* str);

  函数说明:putenv用来改变或者增加环境变量的内容

  参数:str的格式为name=value,若环境原先存在,则环境变量值会依参数str改变,若不存在,则增加该环境变量

  返回值:成功返回0,错误返回-1.

     3.拓展

        setenv函数

  头文件:#include<stdlib.h>

  函数原型: int setenv(const char* name, const char* value, int overwrite)

  函数说明:setenv用来改变或者增加环境变量

  参数:name为环境变量名称字符串。 value则为变量内容,overwrite用来决定是否要改变已存在的环境变量。如果overwrite不为0,而该环境变量原已有内容,则原内容会被改为参数value所指的变量内容。如果overwrite为0,且该环境变量已有内容,则参数value会被忽略。

  返回值:成功返回0,错误返回-1.

2.snprintf

        1.描述

        snprintf() 是一个 C 语言标准库函数,用于格式化输出字符串,并将结果写入到指定的缓冲区,与 sprintf() 不同的是,snprintf() 会限制输出的字符数,避免缓冲区溢出。

        C 库函数 int snprintf(char *str, size_t size, const char *format, ...) 设将可变参数(...)按照 format 格式化成字符串,并将字符串复制到 str 中,size 为要写入的字符的最大数目,超过 size 会被截断,最多写入 size-1 个字符。

        与sprintf()函数不同的是,snprintf() 函数提供了一个参数 size,可以防止缓冲区溢出。如果格式化后的字符串长度超过了 size-1,则 snprintf() 只会写入 size-1 个字符,并在字符串的末尾添加一个空字符(\0)以表示字符串的结束。

        2.函数原型

int snprintf ( char * str, size_t size, const char * format, ... );

        3.参数意义 

  • str -- 目标字符串,用于存储格式化后的字符串的字符数组的指针。
  • size -- 字符数组的大小。
  • format -- 格式化字符串。
  • ... -- 可变参数,可变数量的参数根据 format 中的格式化指令进行格式化。

      4.返回值

        snprintf() 函数的返回值是输出到 str 缓冲区中的字符数,不包括字符串结尾的空字符 \0。如果 snprintf() 输出的字符数超过了 size 参数指定的缓冲区大小,则输出的结果会被截断,只有 size - 1 个字符被写入缓冲区,最后一个字符为字符串结尾的空字符 \0。

        需要注意的是,snprintf() 函数返回的字符数并不包括字符串结尾的空字符 \0,因此如果需要将输出结果作为一个字符串使用,则需要在缓冲区的末尾添加一个空字符 \0。

3.strtok

        1.描述

        C 库函数 char *strtok(char *str, const char *delim) 分解字符串 str 为一组字符串,delim 为分隔符。

        2.函数原型

char *strtok(char *str, const char *delim)

        3.参数意义 

  • str -- 要被分解成一组小字符串的字符串。
  • delim -- 包含分隔符的 C 字符串。

        4.返回值 

        该函数返回被分解的第一个子字符串,如果没有可检索的字符串,则返回一个空指针。 

4.chdir

        1.描述

                修改当前进程的路径

        2.函数原型

 int chdir(const char *path);

5.strerror

        1.描述

        C 库函数 char *strerror(int errnum) 从内部数组中搜索错误号 errnum,并返回一个指向错误消息字符串的指针。strerror 生成的错误字符串取决于开发平台和编译器。

         2.函数原型:

char *strerror(int errnum)

         3.参数意义 

  • errnum -- 错误号,通常是 errno

        4.返回值 

该函数返回一个指向错误字符串的指针,该错误字符串描述了错误 errnum。 

6.fgets

        1.描述:

        C 库函数 char *fgets(char *str, int n, FILE *stream) 从指定的流 stream 读取一行,并把它存储在 str 所指向的字符串内。当读取 (n-1) 个字符时,或者读取到换行符时,或者到达文件末尾时,它会停止,具体视情况而定。

        2.函数原型:

char *fgets(char *str, int n, FILE *stream)

        3.参数意义

  • str -- 这是指向一个字符数组的指针,该数组存储了要读取的字符串。
  • n -- 这是要读取的最大字符数(包括最后的空字符)。通常是使用以 str 传递的数组长度。
  • stream -- 这是指向 FILE 对象的指针,该 FILE 对象标识了要从中读取字符的流。

        4.返回值

        如果成功,该函数返回相同的 str 参数。如果到达文件末尾或者没有读取到任何字符,str 的内容保持不变,并返回一个空指针。

如果发生错误,返回一个空指针。

7.宏函数

#define SKipPath(p) do{ p+= (strlen(p) - 1); while(*p != '/') --p;}while(0)

8.代码

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <string.h>
#include <errno.h>#define SIZE 512
#define ZERO '\0'
#define SEP " " 
#define NUM 32
#define SKipPath(p) do{ p+= (strlen(p) - 1); while(*p != '/') --p;}while(0)char cwd[SIZE * 2];
char *Gargc[NUM];
int lastcode = 0;void Die()
{exit(1);
}const char *GetHome()
{const char *home = getenv("HOME");if(home == NULL) return "/";return home;
}const char *GetUserName()
{const char* name = getenv("USER");if(name == NULL) return "None";return name;
}const char *GetHostName()
{const char* hostname = getenv("HOSTNAME");if(hostname == NULL) return "None";return hostname;
}const char *GetPwd()
{const char* pwd = getenv("PWD");if(pwd == NULL) return "None";return pwd;
}//Command line output
void MakeCommandLineAndPrint()
{char CommandLine[SIZE];int size = sizeof(CommandLine);const char *name = GetUserName();const char *hostname = GetHostName();const char *pwd = GetPwd();SKipPath(pwd);snprintf(CommandLine, size, "[%s@%s %s]> ", name, hostname, strlen(cwd) == 1 ? "/" : pwd + 1); printf("%s",CommandLine);fflush(stdout);
}//User Command line input
int GetUserCommandLine(char *UserCommandLine, size_t size)
{char *s = fgets(UserCommandLine, size, stdin);if(s == NULL) return -1;s[strlen(UserCommandLine) - 1] = ZERO;return strlen(UserCommandLine);
}void SplitCommandLine(char *UserCommandLine, size_t size)
{(void)size;Gargc[0] = strtok(UserCommandLine, SEP);int index = 1;while((Gargc[index++] = strtok(NULL, SEP)));
}void ExecuteCommand()
{pid_t id =fork();if(id < 0) Die();else if(id == 0){//childexecvp(Gargc[0], Gargc);exit(errno);}else{//fatherint status = 0;pid_t rid = waitpid(id, &status, 0);if(rid > 0){//father dolastcode = WEXITSTATUS(status);if(lastcode != 0) printf("%s:%s:%d\n",Gargc[0],strerror(lastcode), lastcode);}}
}void cd()
{const char* path = Gargc[1];if(path == NULL)path = GetHome();// path == Gargc[1]chdir(path);//Refresh the environment variableschar tmp[SIZE * 2];getcwd(tmp, sizeof(tmp));snprintf(cwd, sizeof(cwd), "PWD=%s", tmp);putenv(cwd);
}int CheckBuildin()
{int yes = 0;const char *enter_cmd = Gargc[0];if(strcmp(enter_cmd, "cd") == 0){yes = 1;cd();}else if(strcmp(enter_cmd, "echo") == 0 && strcmp(Gargc[1], "$") == 0){yes = 1;printf("%d\n",lastcode);lastcode = 0;}return yes;
}int main()
{int quit = 0;while(!quit){//1. We need a command line that we output ourselvesMakeCommandLineAndPrint();//2. Get the user command stringchar UserCommandLine[SIZE];int n = GetUserCommandLine(UserCommandLine, sizeof(UserCommandLine));if(n <= 0) return 1;//3. Command-line string splittingSplitCommandLine(UserCommandLine, sizeof(UserCommandLine));//4. Check if the command has built-in commandsn = CheckBuildin();if(n) continue; //5. Execute the commandExecuteCommand();}  return 0;  
}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.shwantai.cn/a/41175758.html

如若内容造成侵权/违法违规/事实不符,请联系万泰站长网进行投诉反馈email:xxxxxxxx@qq.com,一经查实,立即删除!

相关文章

SpringBoot整合Knife4j

✅作者简介:大家好,我是Leo,热爱Java后端开发者,一个想要与大家共同进步的男人😉😉🍎个人主页:Leo的博客💞当前专栏: 循序渐进学SpringBoot ✨特色专栏: MySQL学习 🥭本文内容:SpringBoot整合Knife4j 📚个人知识库: Leo知识库,欢迎大家访问 目录 1.前言☕…

54 npm run serve 和 npm run build 输出的关联和差异

前言 通常来说 我们开发的时候一般会用到的命令是 “npm run serve”, “npm run build” 前者会编译当前项目, 然后将编译之后的结果以 node 的形式启动一个服务, 暴露相关业务资源, 因此 我们可以通过 该服务访问到当前项目 后者是编译当前项目, 然后做一下最小化代码的优…

SmartChart的部署以及可能遇见的报错解决方案

简介 数据可视化是一种将数据转化为图形的技术&#xff0c;可以帮助人们更好地理解和分析数据。但是&#xff0c;传统的数据可视化开发往往需要编写大量的代码&#xff0c;或者使用复杂的拖拽工具&#xff0c;不仅耗时耗力&#xff0c;而且难以实现个性化的需求。有没有一种更…

Linux:Jenkins:参数化版本回滚(6)

上几章我讲到了自动集成和部署 Linux&#xff1a;Jenkins全自动持续集成持续部署&#xff08;4&#xff09;-CSDN博客https://blog.csdn.net/w14768855/article/details/136977106 当我们觉得这个页面不行的时候&#xff0c;需要进行版本回滚&#xff0c;回滚方法我这里准备了…

强大Python开发工具 WingPro for Mac v10.0.3注册激活版

WingPro for Mac是一款专为Mac用户设计的强大Python开发工具&#xff0c;它集成了丰富的功能和工具&#xff0c;帮助开发者更高效地编写、调试和管理Python代码。 软件下载&#xff1a;WingPro for Mac v10.0.3注册激活版下载 首先&#xff0c;WingPro for Mac提供了直观易用的…

ubuntu23.10配置RUST开发环境

系统版本: gcc版本 下载rustup安装脚本: curl --proto https --tlsv1.2 https://sh.rustup.rs -sSf | sh下载完成后会自动执行 选择默认安装选项 添加cargo安装目录到环境变量 vim ~/.bashrc 默认已添加 使用环境变量立即生效 source ~/.bashrc 执行rust开发环境,在终端输入…