【Linux】进程篇(补):简易 shell 的实现(进程深刻理解、内建命令的使用)

文章目录

  • makefile
  • mybash.c


代码逻辑框架(重要的是,边写边查!)

  1. 命令行提示符,fflush 刷新显示
  2. 获取 输入的 有效字符串,定义一个字符数组,用 fgets 从键盘上获取(注意处理命令行输入时的回车)
  3. 字符串切割,C语言函数 strtok,子串保存到指针数组
  4. 创建子进程,执行代码

细节:

  1. ls 的配色方案

  2. 内建命令的处理

  • cd .. cd / 这样的命令,需要让 bash 自己执行的,叫做 内建命令 / 内置命令
  • export,一般用户自定义的环境变量,在 bash 中要用户自己来进行维护,不要用一个经常被覆盖的缓冲区来保存环境变量!!!
  • env,我们一般需要 env 时,都要查看的是自己进程的环境列表,这里就是查看 bash 的环境列表。
  • echo,利用指针查找和输出
  • echo $?

其实我们之前提到过的几乎所有环境变量命令,都是 内建命令。


makefile


mybash:mybash.c
	gcc -o $@ $^
.PHONY:clean
clean:
	rm -f mybash

mybash.c


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

#define MAX 1024
#define ARGC 64
#define SEP " "

int split(char *commandstr, char *argv[])
{
    assert(commandstr);
    assert(argv);

    argv[0] = strtok(commandstr, SEP);
    if(argv[0] == NULL) return -1;
    int i = 1;
    while((argv[i++] = strtok(NULL, SEP)));
    //int i = 1;
    //while(1)
    //{
    //    argv[i] = strtok(NULL, SEP);
    //    if(argv[i] == NULL) break;
    //    i++;
    //}
    return 0;
}

void debugPrint(char *argv[])
{
    for(int i = 0; argv[i]; i++)
    {
        printf("%d: %s\n", i, argv[i]);
    }
}

void showEnv()
{
    extern char **environ;
    for(int i = 0; environ[i]; i++) printf("%d:%s\n", i, environ[i]);
}

int main()
{
    //当我们在进行 env 查看的时候,我们想查的是谁的环境变量列表?父进程 bash 的环境变量列表
    int last_exit = 0;
    char myenv[32][256];
    int env_index = 0;

    while(1)
    {
        char commandstr[MAX] = {0};		// 命令行输入的,完整字符串
        char *argv[ARGC] = {NULL};		// 命令行输入的,子串
        
        // 1
        printf("[Stella@hostname currpath]# ");
        fflush(stdout);		// 把数据从缓冲区刷新显示出来
        
        // 2
        char *s = fgets(commandstr, sizeof(commandstr), stdin);
        assert(s);
        (void)s; // 保证在release方式发布的时候,因为去掉assert了,所以s就没有被使用,而带来的编译告警, 什么都没做,但是充当一次使用
        // abcd\n\0
        commandstr[strlen(commandstr)-1] = '\0';
        
        // 3
        // "ls -a -l" -> "ls" "-a" "-l"
        int n = split(commandstr, argv);
        if(n != 0) continue;
        //debugPrint(argv);
    
        // (1)【添加 ls 命令的配色方案】
        if(strcmp(argv[0], "ls") == 0)	
        {
            int pos = 0;
            while(argv[pos]) pos++;
            argv[pos++] = (char*)"--color=auto";加配色方案
            argv[pos] = NULL; // 比较安全的做法
        }
        // (2)【内建命令】
        // cd .. / cd /: 让bash自己执行的命令,我们称之为 内建命令/内置命令
        if(strcmp(argv[0], "cd") == 0)
        {
            //说到底,cd 命令,重要的表现就如同 bash 自己调用了对应的函数
            if(argv[1] != NULL) chdir(argv[1]);	// chdir是一个系统调用函数,可以改变当前工作路径
            continue;
        }
        else if(strcmp(argv[0], "export") == 0) // 其实我们之前学习到的所有的(几乎)环境变量命令,都是内建命令
        {
            if(argv[1] != NULL){
                strcpy(myenv[env_index], argv[1]);
                putenv(myenv[env_index++]);
            }
            continue;
        }
        else if(strcmp(argv[0], "env") == 0)
        {
            showEnv();
            continue;
        }
        else if(strcmp(argv[0], "echo") == 0)
        {
            // echo $PATH
            const char *target_env = NULL;
            if(argv[1][0] == '$') 
            {
                if(argv[1][1] == '?'){
                    printf("%d\n", last_exit);
                    continue;
                }
                else target_env = getenv(argv[1]+1); // "abcdefg
                
                if(target_env != NULL) printf("%s=%s\n", argv[1]+1, target_env);
            }
            continue;
        }

        
		// 4
		// version 1
        pid_t id = fork();
        assert(id >= 0);
        (void)id;

        if(id == 0)
        {
            if(redir_type != REDIR_NONE)
            {
               //1. 存在文件的
               //2. redir_type获取到
               //3. dup2;
            }
            //child
            execvp(argv[0], argv);
            exit(1);
        }
        int status = 0;
        pid_t ret = waitpid(id, &status, 0);
        if(ret > 0){
            last_exit = WEXITSTATUS(status);
        }
        //printf("%s\n", commandstr);
    }
}

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

简化Java单元测试数据

用EasyModeling简化Java单元测试 EasyModeling 是我在2021年圣诞假期期间开发的一个 Java 注解处理器&#xff0c;采用 Apache-2.0 开源协议。它可以帮助 Java 单元测试的编写者快速构造用于测试的数据模型实例&#xff0c;简化 Java 项目在单元测试中准备测试数据的工作&…

C++ ——STL容器【list】模拟实现

代码仓库&#xff1a; list模拟实现 list源码 数据结构——双向链表 文章目录 &#x1f347;1. 节点结构体&#x1f348;2. list成员&#x1f349;3. 迭代器模板&#x1f34a;4. 迭代器&#x1f34b;5. 插入删除操作&#x1f34c;5.1 insert & erase&#x1f34c;5.2 push_…

flask处理表单数据

flask处理表单数据 处理表单数据在任何 web 应用开发中都是一个常见的需求。在 Flask 中&#xff0c;你可以使用 request 对象来获取通过 HTTP 请求发送的数据。对于 POST 请求&#xff0c;可以通过 request.form 访问表单数据。例如&#xff1a; from flask import Flask, r…

电子鼻毕业论文

面向压埋探测的人体代谢气体识别方法的研究与应用 实现对非目标气体的检测 数据预处理 &#xff08;1a&#xff09;标准化 将采集到的数据先进行变换&#xff0c;统一数量级。其中&#xff0c;xij为第j个传感器的第i个采样值&#xff1b;xj为第 j 个气体传感器的所有采样值&…

Java课题笔记~Maven基础

2、Maven 基础 2.1 Maven安装与配置 下载安装 配置&#xff1a;修改安装目录/conf/settings.xml 本地仓库&#xff1a;存放的是下载的jar包 中央仓库&#xff1a;要从哪个网站去下载jar包 - 阿里云的仓库 2.2 创建Maven项目

计算机网络——学习笔记

付费版&#xff1a;直接在上面的CSDN资源下载 免费版&#xff1a;https://wwsk.lanzouk.com/ijkcj13tqmyb 有疑问或者错误的地方可以在评论区指出&#xff0c;我会尽快回复 示例图&#xff1a;

SOC FPGA之HPS模型设计(一)

目录 一、建立HPS硬件系统模型 1.1 GHRD 1.2 从0开始搭建HPS 1.2.1 FPGA Interfaces 1.2.1.1 General 1.2.1.2 AXI Bridge 1.2.1.3 FPGA-to-HPS SDRAM Interface 1.2.1.4 DMA Peripheral Request 1.2.1.5 Interrupts 1.2.1.6 EMAC ptp interface 1.2.2 Peripheral P…

[JAVAee]线程池

目录 线程池的作用 线程池的使用 线程池的创建方式 线程池的解析 ①Executors与ThreadPoolExecutor ②ThreadPoolExecutor线程池的构造方法 ③RejectedExecutionHandler线程池的拒绝策略 固定线程数量线程池的简单模拟实现 线程池的作用 对于线程的使用,可能会频繁的创建…

首批!棱镜七彩通过汽车云-汽车软件研发效能成熟度模型能力评估

2023年7月25-26日&#xff0c;由中国信息通信研究院、中国通信标准化协会联合主办的“2023年可信云大会”隆重召开。会上&#xff0c;在中国信息通信研究院云计算与大数据研究所副所长栗蔚的主持下&#xff0c;中国信通院发布了“2023年上半年可信云评估结果”&#xff0c;并由…

uniapp checkbox radio 样式修改

文章目录 通过查看代码&#xff0c;发现 before部分是设置样式的主要属性 我们要设置的话&#xff0c;就要设置checkbox::before的属性。 其中的content表示内容&#xff0c;比如内部的对勾 那么我们设置的时候&#xff0c;比如设置disabletrue的时候或者checkedtrue的时候&…

onnxruntime (C++/CUDA) 编译安装

一、克隆及编译 git clone --recursive https://github.com/Microsoft/onnxruntime cd onnxruntime/ git checkout v1.8.0如果克隆的时候报错&#xff1a; 执行以下&#xff1a; apt-get install gnutls-bin git config --global http.sslVerify false git config --global h…

Git初始化

查看git版本 git --version 设置Git的配置变量 方法&#xff1a; 修改全局文件&#xff08;用户主目录下.gitconfig&#xff09;修改系统文件&#xff08;如/etc/gitconfig&#xff09; 用户姓名和邮件地址 修改用户名和邮件地址 git config --global user.name "用…

《JeecgBoot系列》JeecgBoot(ant-design-vue)实现筛选框:支持下拉搜索+下拉多选+表字典(支持条件查询)功能

JeecgBoot(ant-design-vue)实现筛选框&#xff1a;支持下拉搜索下拉多选表字典(支持条件查询)功能 JSearchMultiSelectTag.vue源文件 一、需求介绍 在使用JeectBoot(ant-design-vue)设计表单时&#xff0c;需要实现下拉搜索下拉多选表字典(支持条件查询)。 但是系统目前有两…

PysparkNote006---pycharm加载spark环境

pycharm配置pyspark环境&#xff0c;本地执行pyspark代码 spark安装、添加环境变量不提了 File-Settings-Project-Project Structure-add content root添加如下两个路径 D:\code\spark\python\lib\py4j-0.10.7-src.zipD:\code\spark\python\lib\pyspark.zip 2023-07-26 阴 于…

linux(进程)[6]

管理概念 先描述&#xff0c;再组织 进程 启动一个软件就相当于启动了一个进程 Linux下执行一条命令就在系统层面创建了一个进程&#xff01;&#xff01; 如何管理 进程对应的代码和数据 进程对应的PCB结构体 PCB&#xff08;process control block&#xff09; 在Linu…

Banana Pi BPI-KVM – 基于 Rockchip RK3568 SoC 的 KVM over IP 解决方案

Banana Pi 已经开始开发基于 Rockchip RK3568 SoC 的 BPI-KVM 盒&#xff0c;但它不是迷你 PC&#xff0c;而是 KVM over IP 解决方案&#xff0c;旨在远程控制另一台计算机或设备&#xff0c;就像您在现场一样&#xff0c;例如能够打开和关闭连接的设备、访问 BIOS 等。 商业…

数据结构之顺序表

一、概念及结构 顺序表是用一段物理地址连续的存储单元依次存储数据元素的线性结构&#xff0c;一般情况下采用数组存 储。在数组上完成数据的增删查改。 顺序表一般可以分为&#xff1a; 1. 静态顺序表&#xff1a;使用定长数组存储元素。 2. 动态顺序表&#xff1a;使用动…

【SEO基础】百度权重是什么意思及网站关键词应该怎么选?

百度权重是什么意思及网站关键词应该怎么选&#xff1f; 正文共&#xff1a;3253字 20图 预计阅读时间&#xff1a;9分钟 ​ 1.什么是网站权重&#xff1f; 这段时间和一些朋友聊到网站权重以及关键词&#xff0c;发现蛮多人对于这两个概念的认知还是存在一些错误的&#xf…

数学分析:流形的线性代数回顾

因为是线性的&#xff0c;所以可以把所有的系数都提取出去。这也是多重线性代数的性质。可以看成基本的各项自变量的乘法。 这里可以看到两个不同基向量下&#xff0c;他们的坐标转化关系。 引出了张量积&#xff0c;也就是前面提到的内容。 对偶空间的例子总是比较美好。 因为…
最新文章