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

linux中myshell的实现

目录

引言

全局信息

核心代码

核心函数


引言

随着计算机技术的飞速发展,操作系统在人们日常工作和生活中扮演着越来越重要的角色。Linux作为一款开源、自由且功能强大的操作系统,已经成为了众多服务器和开发者的首选平台。Shell作为Linux系统的用户界面,为用户提供了执行命令、管理文件、自动化任务等功能。

在本项目中,我们将实现一个简单的Shell程序——myshell。在myshell中,将模拟shell如何进程执行内建指令、普通指令与进程切换。

全局信息

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <assert.h>
#include <unistd.h>
#include <stdlib.h>
#include <sys/types.h>
#include <sys/wait.h>#define LEFT "["
#define RIGHT "]"
#define LABLE "#"
#define DELIM " \t"
#define LINE_SIZE 1024
#define ARGC_SIZE 32
#define EXIT_CODE 44int lastcode = 0;
int quit = 0;
extern char **environ;
char commandline[LINE_SIZE];
char *argv[ARGC_SIZE];
char pwd[LINE_SIZE];// 自定义环境变量表
char myenv[LINE_SIZE];

我们将特定的元素定义为宏,方便代码的理解与阅读。

核心代码

主体分为:指令的交互(打印对话栏,获取指令字符串)

                  指令字符串的拆解

                  判断是否为内建指令

                  不是内建指令,将进行frok执行

                                                在循环中,不断进行交互

int main()
{while(!quit){// 2. 交互问题,获取命令行, ls -a -l > myfile / ls -a -l >> myfile / cat < file.txtinteract(commandline, sizeof(commandline));// commandline -> "ls -a -l -n\0" -> "ls" "-a" "-l" "-n"// 3. 子串分割的问题,解析命令行int argc = splitstring(commandline, argv);if(argc == 0) continue;// 4. 指令的判断 //内键命令,本质就是一个shell内部的一个函数int n = buildCommand(argv, argc);// 5. 普通命令的执行if(!n) NormalExcute(argv);}return 0;
}

核心函数

1.交互


const char *getusername()
{return getenv("USER");
}const char *gethostname()
{return getenv("HOSTNAME");
}void getpwd()
{getcwd(pwd, sizeof(pwd));   //#include <unistd.h>    char* getcwd(char* buf, size_t size);  //buf是一个输出型参数,size是buf的大小,返回值是buf指向的字符串的地址。
}void interact(char *cline, int size)
{getpwd();printf(LEFT"%s@%s %s"RIGHT""LABLE" ", getusername(), gethostname(), pwd);char *s = fgets(cline, size, stdin);assert(s);(void)s;// "abcd\n\0"cline[strlen(cline)-1] = '\0';
}

2.拆解


// ls -a -l | wc -l | head 
int splitstring(char cline[], char *_argv[])
{int i = 0;argv[i++] = strtok(cline, DELIM);while(_argv[i++] = strtok(NULL, DELIM)); // 故意写的=return i - 1;
}

3.普通指令

子进程执行,父进程等待


void NormalExcute(char *_argv[])
{pid_t id = fork();if(id < 0){perror("fork");return;}else if(id == 0){//让子进程执行命令//execvpe(_argv[0], _argv, environ);execvp(_argv[0], _argv);exit(EXIT_CODE);}else{int status = 0;pid_t rid = waitpid(id, &status, 0);if(rid == id) {lastcode = WEXITSTATUS(status);}}
}

4.内建指令


int buildCommand(char *_argv[], int _argc)
{if(_argc == 2 && strcmp(_argv[0], "cd") == 0){chdir(argv[1]);getpwd();sprintf(getenv("PWD"), "%s", pwd);return 1;}else if(_argc == 2 && strcmp(_argv[0], "export") == 0){strcpy(myenv, _argv[1]);putenv(myenv);return 1;}else if(_argc == 2 && strcmp(_argv[0], "echo") == 0){if(strcmp(_argv[1], "$?") == 0){printf("%d\n", lastcode);lastcode=0;}else if(*_argv[1] == '$'){char *val = getenv(_argv[1]+1);if(val) printf("%s\n", val);}else{printf("%s\n", _argv[1]);}return 1;}// 特殊处理一下lsif(strcmp(_argv[0], "ls") == 0){_argv[_argc++] = "--color";_argv[_argc] = NULL;}return 0;
}

列举了export建立环境变量、echo打印、cd改变路径等信息        

建立环境变量只需要

 else if(_argc == 2 && strcmp(_argv[0], "export") == 0){
     strcpy(myenv, _argv[1]);
     putenv(myenv);
     return 1;

在bash中putenv即可。

注意:

putenv只是修改了环境变量表的一个指针,让他指向了这个区域。但是这个区域改变之后,就无法获得对应的环境变量。

因此我们需要将区域固定住,额外开辟了一个myenv的空间(cline是变化的)。


http://www.mrgr.cn/news/58999.html

相关文章:

  • 基于vite和vue3、 eslint、prettier、stylelint、husky规范
  • LeetCode392:判断子序列
  • 解决电脑更改IP地址后无法连接网络的实用指南
  • Pandas模块之垂直或水平交错条形图
  • Codeforces Round 981 (Div. 3) A-D
  • 【小白学机器学习16】 概率论的世界观2: 从正态分布去认识世界
  • 长短期记忆网络(LSTM)详解
  • unity游戏开发之塔防游戏
  • 词云图大师支持词云图字体预览,轻松选择字体样式!
  • list 的实现
  • SQL语句的书写顺序与实际执行顺序的差异,以及如何利用执行顺序优化查询性能
  • SpringBoot中EasyExcel使用实践总结
  • 【Java】java 集合框架(详解)
  • 电脑连接海康相机并在PictureBox和HWindowControl中分别显示。
  • 开源数据库 - mysql - 组织结构(与oracle的区别)
  • 系统调用的介绍
  • 每日“亿“题 东方博宜OJ 1538 - 小 X 与煎饼达人(flip)
  • 线程安全介绍
  • 代码随想录算法训练营第55天|最小生成树:prim、kruskal算法
  • 密码管理APP需求分析报告
  • 苍穹外卖总结
  • SaaS诊所云平台管理系统源码,采用Vue 2+Spring Boot+MyBatis技术开发,开箱即用。
  • 如何与家人相处 林曦老师有话说
  • cisp考试多久出结果?cisp认证考试指南,零基础入门到精通,收藏这篇就够了
  • 部署DNS主从服务器
  • jclasslib插件使用细节