[Linux入门]---使用exec函数实现简易shell

news2024/12/27 13:22:23

文章目录

  • 1.简易实现
  • 2.人机交互,获取命令行
  • 3.命令行分割
  • 4.执行命令
  • 5.内建命令
  • 6.myshell代码

1.简易实现

2.人机交互,获取命令行

代码如下:

int quit=0;
#define LEFT "["
#define RIGHT "]"
#define LABLE "#"
#define LINE_SIZE 1024

char pwd[LINE_SIZE];
char commandline[LINE_SIZE];

const char* getusername()
{
    return getenv("USER");
}

void getpwd()
{
    getcwd(pwd, sizeof(pwd));
}
void interact(char* cline, int size)
{
    //获取主机名
    char hostname[256];
    gethostname(hostname, sizeof(hostname));
    //获取当前路径
    getpwd();
    printf(LEFT"%s@%s %s"RIGHT""LABLE" ", getusername(),hostname, pwd);
    char* s = fgets(cline, size, stdin);
    assert(s);//debug版本下assert才起效果
    //release,assert失效
    (void)s;//使用一下,可以在不同版本都生效,抵挡编译器报警

    //"abcd\n\0"
    cline[strlen(cline)-1] = '\0';
}
int main()
{
	while(!quit)
	{
	    //交互问题,获取命令行
    	interact(commandline,sizeof(commandline));
    	printf("%s\n",commandline );
    }
    return 0;
}

代码运行的的结果为:
在这里插入图片描述
运行结果如上,程序获取命令行以及提示行显示的功能已经完成了。

3.命令行分割

代码如下:

#define DELIM " "
#define ARGC_SIZE 32

char* argv[ARGC_SIZE];


int splitstring(char cline[], char* _argv[])
{
    int i = 0;
    _argv[i++] = strtok(cline, DELIM);
    //stork函数扫描字符串末尾时,返回空指针
    while(_argv[i++] = strtok(NULL,DELIM));//故意写的=

    return i - 1;
}
int main()
{
    while(!quit)
    {
        //交互问题,获取命令行
        interact(commandline,sizeof(commandline));

        //3.子串分割问题,解析命令行
        
        int argc = splitstring(commandline,argv);
        if(argc == 0) continue;
        
        for(int i = 0; i < argc; i++)
        {
            printf("%s\t",argv[i]);
        }
        
        printf("\n");
    }
    return 0;
}

代码运行的的结果为:
在这里插入图片描述
运行结果如上,命令行分割成字符串并存放进入数组使用。

4.执行命令

代码如下:

#define EXIT_CODE 44

int lastcode = 0;

void NormalExcute(char* _argv[])
{
    pid_t id = fork();
    if(id < 0)
    {
        perror("fork");
        return;
    }
    else if(id == 0)
    {
        //让子进程执行命令
        execvp(_argv[0],_argv);
        exit(EXIT_CODE);
    }
    else
    {
        int status = 0;
        pid_t rid = waitpid(id, &status,0);
        if(rid == id)
        {
            lastcode = WEXITSTATUS(status);
        }
    }
}
int main()
{
    while(!quit)
    {
        //1.交互问题,获取命令行
        interact(commandline,sizeof(commandline));

        //2.子串分割问题,解析命令行
        
        int argc = splitstring(commandline,argv);
        if(argc == 0) continue;
        

        for(int i = 0; i < argc; i++)
        {
            //printf("%d:",i);
            //printf("%s\n",argv[0]);
            printf("%s\n",argv[i]);
        }
        
        printf("\n");
        
        
        //3.普通命令的执行
        //if(!n)
        NormalExcute(argv);
    }
    return 0;
}

代码运行的结果:
在这里插入图片描述
运行结果如上,可以让子进程执行替换函数,调用系统程序命令执行!

5.内建命令

在这里插入图片描述
我们发现使用一些命令的时候没有结果,诸如“”cd\echo”等命令,因为这些命令属于内建命令,是要父进程执行的。
代码如下:

#define EXIT_CODE 44


int lastcode = 0;

//自定义环境变量表
char myenv[LINE_SIZE];
//自定义本地变量表

int buildCommand(char* _argv[], int _argc)
{
    if(_argc == 2 && strcmp(_argv[0], "cd") == 0)
    {
        //修改父进程中的当前路径
        chdir(argv[1]);
        //把修改路径放到pwd数组中
        getpwd();
        //把pwd数组的路径,放到环境变量中
        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);
        }
        return 1;
    }

    //特殊处理一下
    if(strcmp(_argv[0], "ls") == 0)
    {
        _argv[_argc++] = "--color";
        _argv[_argc] = NULL;
    }

    return 0;
}
int main()
{
    while(!quit)
    {
        //1.交互问题,获取命令行
        interact(commandline,sizeof(commandline));

        //2.子串分割问题,解析命令行
        
        int argc = splitstring(commandline,argv);
        if(argc == 0) continue;
        

        for(int i = 0; i < argc; i++)
        {
            //printf("%d:",i);
            //printf("%s\n",argv[0]);
            printf("%s\n",argv[i]);
        }
        
        printf("\n");
        
        //指令的判断
        //内建命令,本质就是一个shell内部的一个函数
        int n = buildCommand(argv, argc);
        
        //3.普通命令的执行
        if(!n) NormalExcute(argv);
    }
    return 0;
}

代码运行的结果如下:
在这里插入图片描述
在执行普通命令之前,我们需要判断是不是内建命令,如果是的话,分析之后让父进程执行!

6.myshell代码

#include <stdio.h>
#include<stdlib.h>
#include<unistd.h>
#include<assert.h>
#include<string.h>
#include<sys/types.h>
#include<sys/wait.h>

#define LEFT "["
#define RIGHT "]"
#define LABLE "#"
#define LINE_SIZE 1024
#define DELIM " "
#define ARGC_SIZE 32
#define EXIT_CODE 44

int quit=0;
char pwd[LINE_SIZE];
char commandline[LINE_SIZE];
char* argv[ARGC_SIZE];
int lastcode = 0;

//自定义环境变量表
char myenv[LINE_SIZE];
//自定义本地变量表

const char* getusername()
{
    return getenv("USER");
}
//const char* gethostname()
//{
//    return getenv("HOSTNAME");
//}
const char* mygethostname()
{
    //char myhostname[LINE_SIZE];

    return getenv("HOSTNAME");
}
void getpwd()
{
    getcwd(pwd, sizeof(pwd));
}
void interact(char* cline, int size)
{
    //获取主机名
    char hostname[256];
    gethostname(hostname, sizeof(hostname));
    //获取当前路径
    getpwd();
    //printf("%s\n",mygethostname());
    //printf(LEFT"%s@%s%s"RIGHT""LABLE" ",getusername(),mygethostname(),pwd);
    printf(LEFT"%s@%s %s"RIGHT""LABLE" ", getusername(),hostname, pwd);
    char* s = fgets(cline, size, stdin);
    assert(s);//debug版本下assert才起效果
    //release,assert失效
    (void)s;//使用一下,可以在不同版本都生效,抵挡编译器报警

    //"abcd\n\0"
    cline[strlen(cline)-1] = '\0';
}

int splitstring(char cline[], char* _argv[])
{
    int i = 0;
    _argv[i++] = strtok(cline, DELIM);
    //stork函数扫描字符串末尾时,返回空指针
    while(_argv[i++] = strtok(NULL,DELIM));//故意写的=

    return i - 1;
}

void NormalExcute(char* _argv[])
{
    pid_t id = fork();
    if(id < 0)
    {
        perror("fork");
        return;
    }
    else if(id == 0)
    {
        //让子进程执行命令
        execvp(_argv[0],_argv);
        exit(EXIT_CODE);
    }
    else
    {
        //创建子进程失败
        int status = 0;
        pid_t rid = waitpid(id, &status,0);
        if(rid == id)
        {
            lastcode = WEXITSTATUS(status);
        }
    }
}
int buildCommand(char* _argv[], int _argc)
{
    if(_argc == 2 && strcmp(_argv[0], "cd") == 0)
    {
        //修改父进程中的当前路径
        chdir(argv[1]);
        //把修改路径放到pwd数组中
        getpwd();
        //把pwd数组的路径,放到环境变量中
        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);
        }
        return 1;
    }

    //特殊处理一下
    if(strcmp(_argv[0], "ls") == 0)
    {
        _argv[_argc++] = "--color";
        _argv[_argc] = NULL;
    }

    return 0;
}
int main()
{
    while(!quit)
    {
        //1.交互问题,获取命令行
        interact(commandline,sizeof(commandline));

        //2.子串分割问题,解析命令行
        
        int argc = splitstring(commandline,argv);
        if(argc == 0) continue;
        
        
        //指令的判断
        //内建命令,本质就是一个shell内部的一个函数
        int n = buildCommand(argv, argc);
        
        //3.普通命令的执行
        if(!n) NormalExcute(argv);
    }
    return 0;
}


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

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

如何免费试用OpenAI o1 preview大模型

OpenAI于 2024 年 9 月 12 日推出 o1&#xff08;以前称为 Strawberry 项目&#xff09; 。这一系列新推理模型旨在更有效地解决复杂问题。ChatGPT Plus 和 Team 用户可以访问 o1-preview 和 o1-mini&#xff0c;但消息量有限。 OpenAI o1-preview与 GPT-o对比 o1-previewGPT…

Excel 基础知识-操作手册2

十、查找与引用函数 Excel中的查找与引用函数非常丰富&#xff0c;以下是一些主要的函数及其使用示例&#xff1a; 1. **VLOOKUP** - 语法&#xff1a;VLOOKUP(lookup_value, table_array, col_index_num, [range_lookup]) - 示例&#xff1a;假设A列是员工编号&#xff0c;B…

27 顺序表 · 链表

目录 一、单链表 &#xff08;一&#xff09;概念 1、节点 2、链表的性质 &#xff08;二&#xff09;单链表的实现 &#xff08;三&#xff09;单链表算法题 1、移除链表元素 2、反转链表 3、链表的中间节点 4、合并两个有序的单链表 5、链表分割 6、链表的回文结构…

pdf怎么加页码?5种pdf添加页码指南分享,快来领取!

如何在一个包含大量页面的大型pdf文件中快速找到特定的页面或信息呢&#xff1f;最简便的方法就是为pdf添加页码。pdf添加页码能够清晰显示页面顺序&#xff0c;帮助读者轻松浏览大型pdf文档&#xff0c;同时也便于寻找特定章节和确定整体长度。然而&#xff0c;并非所有pdf文件…

VirtualBox Install MacOS

环境搭建 git clone https://github.com/myspaghetti/macos-virtualbox 脚本配置 修改macos-guest-virtualbox.sh部分内容为 vm_name"macOS" # name of the VirtualBox virtual machine macOS_release_name"Catalina" # install &quo…

PHP 环境搭建教程

搭建一个稳定的PHP开发环境是开发Web应用的基础。在Linux系统上&#xff0c;LAMP&#xff08;Linux, Apache, MySQL/MariaDB, PHP&#xff09;堆栈是最广泛使用的组合。本文将详细介绍如何在Linux上搭建PHP开发环境&#xff0c;涵盖安装步骤、配置和测试。更多内容&#xff0c;…

Docker操作MySQL

1&#xff0c;拷贝&#xff1b; docker cp mysql01:/etc/mysql .2&#xff0c;修改conf.d和mysql.conf.d文件 3&#xff0c; vim mysql/my.cnf 4&#xff0c;拷贝并替换my.cnf文件 5&#xff0c;mysql镜像重启命令&#xff1a; docker exec -it mysql01 -uroot -p0000006&…

LOAM学习

LOAM Ceres Solver 中的LocalParameterization理解ALOAM雷达里程计主要步骤论文A-LOAM laser Odometry代码LiDAR Odometry寻找角点特征代码流程分析寻找面点特征 求解器设置 Ceres Solver 中的LocalParameterization理解 该LocalParameterization类用来解决非线性优化中的过参…

最全的软件测试面试题(含答案)

软件的生命周期(prdctrm) 计划阶段(planning)-〉需求分析(requirement)-〉设计阶段(design)-〉编码(coding)->测试(testing)->运行与维护(running maintrnacne) 测试用例 用例编号  测试项目  测试标题  重要级别  预置条件  输入数据  执行步骤   预期结果 1…

python做游戏好用吗

Python做游戏是完全可以的&#xff0c;而且也非常简单&#xff0c;有一个专门针对游戏开发的平台&#xff08;模块&#xff09;—pygame&#xff0c;允许开发人员快速设计游戏而又摆脱了低级语言的束缚&#xff0c;下面我简单介绍一下这个模块的安装和使用&#xff1a; 1、首先…

Java手写RPC框架-01-开篇

项目背景 随着业务不断升级&#xff0c;系统规模不断扩大&#xff0c; 单体架构会产生越来越多的问题&#xff0c;需要引入微服务将原先架构解耦为一个个模块。每个服务模块放在不同的服务器上&#xff0c;能够保证系统在高并发环境下的正常运转。 各个服务模块之间如何相互调…

想了解医疗大模型吗?请看《智能系统学报》实验室最新综述论文

本文改编自实验室的最新综述论文《医疗领域的大型语言模型综述》&#xff0c;该论文发表于《智能系统学报》。《智能系统学报》是中国人工智能学会会刊、“中国人工智能学会推荐中文学术期刊”列表中的A类期刊。该论文合作单位包括上海理工大学、上海儿童医学中心、复旦大学附属…

LangChain-Chatchat本地搭建部署

文章目录 前言一、安装部署1.软硬件要求2. 安装 Langchain-Chatchat3.安装Xinference4.遇到的问题问题1&#xff1a;Failed building wheel for llama-cpp-python问题2&#xff1a;Failed building wheel for pynini问题3&#xff1a;运行xinference错误 二、初始化项目配置并运…

了解软件测试的概念

本文我们来了解软件测试 的一些基本概念。同时需要记住衡量软件测试结果的依据—需求&#xff1b; 1. 需求的概念 满足用户期望或正式规定文档&#xff08;合同、标准、规范&#xff09;所具有的条件和权能&#xff0c;包含用户需求和软件需求。&#xff08;其实就是客户想要软…

摩尔信使MThings逻辑控制实例——交通灯

摩尔信使MThings提供了强大的数据配置和逻辑控制功能&#xff0c;可为用户带来一种高效且直观的方式进行管理和控制交通灯系统。与传统的PLC&#xff08;可编程逻辑控制器&#xff09;相比&#xff0c;MThings的界面更加用户友好&#xff0c;使得即使是非专业的用户也能够轻松地…

在 Mac 中设置环境变量

目录 什么是环境变量&#xff0c;为什么它们重要&#xff1f;什么是环境变量&#xff1f;举个例子 如何查看环境变量如何设置和修改环境变量1. 临时设置环境变量2. 永久设置环境变量3. 修改现有环境变量 环境变量在开发中的应用在 Node.js 项目中使用环境变量在 Python 项目中使…

Certificate has expired(npm 安装strapi)

报错信息 解决方法 1、清空缓存&#xff0c;有时&#xff0c;损坏的缓存会导致连接问题 npm cache clean --force 2、切换到淘宝镜像源的 npm 注册表 npm config set registry https://registry.npmmirror.com/ 执行这两步后就可以执行自己想要安装的东西了&#xff0c;我是在执…

Uniapp + Vue3 + Vite +Uview + Pinia 实现购物车功能(最新附源码保姆级)

Uniapp Vue3 Vite Uview Pinia 实现购物车功能&#xff08;最新附源码保姆级&#xff09; 1、效果展示2、安装 Pinia 和 Uview3、配置 Pinia4、页面展示 1、效果展示 2、安装 Pinia 和 Uview 官网 https://pinia.vuejs.org/zh/getting-started.html安装命令 cnpm install pi…

云轴科技ZStack 获鲲鹏应用创新大赛2024上海赛区决赛一等奖

9月13日&#xff0c;鲲鹏应用创新大赛2024上海赛区决赛成功举办。经评委专家从方案创新性、技术领先性、商业前景以及社会价值四个维度严格评审&#xff0c;云轴科技ZStack参赛作品《ZStack鲲鹏原生开发方案》荣获上海赛区企业赛——原生开发赛道&#xff08;互联网&#xff09…

AI大模型系统实战:挑战与应用多领域,人工智能大模型的实际应用场景

AI大模型系统实战&#xff1a;挑战与应用多领域&#xff0c;人工智能大模型的实际应用场景 人工智能的新浪潮中&#xff0c;大模型系统已成为技术革新的重要驱动力。它们以其强大的学习能力和广泛的应用场景&#xff0c;正在重新定义我们与机器交互的方式。本文将深入探讨AI大模…