【Linux】进程_9

文章目录

  • 五、进程
    • 12. 自定义shell
      • 完整程序
  • 未完待续


五、进程

12. 自定义shell

根据我们之前学的知识,这里来编写一个 shell 程序。

在这里插入图片描述
在这里插入图片描述

#include<stdio.h>                                                                                  
#include<stdlib.h>
#include<string.h>
#include<unistd.h>

#define SIZE 1024
#define MAX_ARGC 64
 
// 用户名
const char* UserName()
{
    char* username = getenv("USER");
    if (username) return username;
    else return "None";
}
// 主机名
const char* HostName()
{                                         
    char* hostname = getenv("HOSTNAME");    
    if (hostname) return hostname;          
    else return "None";                     
}                                         
// 路径                                   
const char* CurrentWorkDir()              
{                                         
    char* currentworkdir = getenv("PWD");   
    if (currentworkdir) return currentworkdir;
	else return "None";
}

上面代码可以通过环境变量接口获取指定信息。我们先输出一下命令行提示符试试看。
在这里插入图片描述
在这里插入图片描述
封装输出命令行提示符的信息和接收用户输入成一个函数。
在这里插入图片描述
我们获取到了用户一行输入的整个字符串,现在需要对这个字符串进行切割。

// 分隔符是空格
#define SEP " "
void Split(char in[])
{
    int i = 0;
    argv[i++] = strtok(in, SEP);
    while (argv[i++] = strtok(NULL, SEP));
 }

当做完以上操作后就可以执行命令了,我们创建一个子进程,让子进程来程序替换为我们要执行的命令。我们封装一下执行命令。
在这里插入图片描述
我们不想自己写的shell程序只跑一遍,所以我们要在主函数里加上死循环。
在这里插入图片描述
在这里插入图片描述
运行比较成功,但是我们发现,使用 cd … 命令却没有反应,这是怎么回事?因为执行cd命令的是子进程而不是我们的shell 。像这种不让子进程来执行的命令,而是让我们的shell执行的命令叫做 内建命令 。我们需要特殊处理一下。

// 获取环境变量
char *Home()
{
    return getenv("HOME");
}

int BuildinCmd()
{
    // 是内建命令则返回1,不是则返回0
    int ret = 0;
    if (strcmp("cd", argv[0]) == 0)                                                                  
    {
        ret = 1;
        char *target = argv[1];
        // cd 空表示进入家目录
        if (!target) target = Home();
        chdir(target);
    }
    return ret;
}

在这里插入图片描述
我们再来测试一下:
在这里插入图片描述
这里已经完成的差不多了,再来处理一下细节问题,比如环境变量没有更新。

// 记录路径字符
char pwd[SIZE];

int BuildinCmd()
{
    int ret = 0;
    if(strcmp("cd", argv[0]) == 0)
    {
        ret = 1;
        char *target = argv[1];
        if(!target) target = Home();
        chdir(target);
        char temp[1024];
        // 获取当前路径
        getcwd(temp, 1024);
        // 写入数组
        snprintf(pwd, SIZE, "PWD=%s", temp);
        // 更新
        putenv(pwd);
    }
}

在这里插入图片描述
在这里插入图片描述
再来测试一下:
在这里插入图片描述
比较完善了。但是实际上内建命令绝对不止 cd 命令,至少还包含 exportecho 等命令。就不再一一赘述了。感兴趣的可以自己再去完善,也可以使ls命令带上颜色等等。

完整程序

#include<stdio.h>
#include<stdlib.h>
#include<string.h>
#include<unistd.h>
#include<sys/types.h>
#include<sys/wait.h>
 
#define SIZE 1024
#define MAX_ARGC 64
#define SEP " "
 
char *argv[MAX_ARGC];
char pwd[SIZE];

// 用户名
const char* UserName()
{
    char* username = getenv("USER");                                                                 
    if (username) return username;
    else return "None";
}
// 主机名
const char* HostName()
{
    char* hostname = getenv("HOSTNAME");
    if (hostname) return hostname;
    else return "None";                                                                              
}
// 路径
const char* CurrentWorkDir()
{
    char* currentworkdir = getenv("PWD");
    if (currentworkdir) return currentworkdir;
    else return "None";
}
// 家目录
char* Home()
{
    return getenv("HOME");
}

int Interactive(char out[], int size)
{
    // 输出命令行提示符
    printf("[%s@%s %s]$ ", UserName(), HostName(), CurrentWorkDir());
    // 接收用户输入
    fgets(out, size, stdin);
    // 去掉最后一个 回车符                                                                           
    out[strlen(out) - 1] = '\0';
    return strlen(out);
}

void Split(char in[])
{
    int i = 0;
    argv[i++] = strtok(in, SEP);
    while (argv[i++] = strtok(NULL, SEP));
}

void Execute()
{
    pid_t id = fork();
    if(id == 0)
    {
        // 让子进程执行命令 文件名 + 选项数组
        execvp(argv[0], argv);                                                                     
        exit(1);
    }
    waitpid(id, NULL, 0);
}

int BuildinCmd()
{
    // 是内建命令则返回1,不是则返回0
    int ret = 0;
    if (strcmp("cd", argv[0]) == 0)
    {
        ret = 1;
        char *target = argv[1];
        // cd 空表示进入家目录
        if (!target) target = Home();
        chdir(target);
        char temp[SIZE];
        getcwd(temp, SIZE);
        snprintf(pwd, SIZE, "PWD=%s", temp);
        putenv(pwd);
    }                                                                                                
    return ret;
}

int main()
{
    while(1)
    {
        char commandline[SIZE];
        int n = Interactive(commandline, SIZE);
        // 空串跳出
        if (n == 0) continue;
        Split(commandline);
        n = BuildinCmd();
        if (n) continue;
        Execute();
    }
    return 0;
}

未完待续

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

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

相关文章

【机器学习】 第1章 概述

一、概念 1.机器学习是一种通过先验信息来提升模型能力的方式。 即从数据中产生“模型”( model )的算法&#xff0c;然后对新的数据集进行预测。 2.数据集&#xff08;Dataset&#xff09;&#xff1a;所有数据的集合称为数据集。 训练集&#xff1a;用来训练出一个适合模…

深度判别特征学习在口音识别中的应用

论文&#xff1a;https://arxiv.org/pdf/2011.12461 代码&#xff1a;https://github.com/coolEphemeroptera/AESRC2020 摘要 使用深度学习框架进行口音识别是一项与深度说话人识别相似的工作&#xff0c;它们都期望为输入语音提供可识别的表示。相比于说话人识别网络学习的个…

【数据结构】线性表之《无头单链表》超详细实现

单链表 一.链表的概念及结构二.顺序表与链表的区别与联系三.单链表的实现1.创建单链表2.初始化单链表3.购买节点4.打印单链表5.插入操作1.头插2.尾插3.给定位置之前插入 6.删除操作1.头删2.尾删3.删除给定位置的结点 7.查找数据8.修改数据9.求单链表长度10.清空单链表11.销毁单…

机器学习课程复习——聚类算法

Q:什么是硬聚类,什么是软聚类? 如果一个样本只能属于一个类,则称为硬聚类(hard clustering); 如果一个样本可以属于多个类,则称为软聚类(soft clustering)。 Q:聚类和分类的区别? 聚类分类学习类型无监督学习方法 不需要事先标记的数据 通过发现数据中的模式或结构来组…

【毕业设计】Django 校园二手交易平台(有源码+mysql数据)

此项目有完整实现源码&#xff0c;有需要请联系博主 Django 校园二手交易平台开发项目 项目选择动机 本项目旨在开发一个基于Django的校园二手交易平台&#xff0c;为大学生提供一个安全便捷的二手物品买卖平台。该平台将提供用户注册和认证、物品发布和搜索、交易信息管理等…

Linux-Https协议

文章目录 前言一、Https协议二、常见的加密方式对称加密非对称加密数据摘要&&数据指纹中间人攻击 三、Https的加密历程方案1-只使用对称加密方案2-只使用非对称加密方案3-双方都使用非对称加密方案4-非对称加密对称加密 四、CA证书什么是CA证书CA证书的合法性如何生成.…

Python9 Tkinter创建GUI

1.Tkinter简单介绍 Tkinter是Python的标准GUI&#xff08;图形用户界面&#xff09;库&#xff0c;提供一种简单的方式来创建窗口程序。Tkinter封装了访问Tk GUI工具包的接口&#xff0c;Tk是一个跨平台的GUI开发库&#xff0c;广泛用于创建图形界面。 使用Tkinter&#xff0…

++++++局部变量、全局变量及变量的存储类别++++====+++指针+++

局部变量、全局变量及变量的存储类别 局部变量与全局变量的基本概念 局部变量&#xff1a;在函数内部定义的变量称为局部变量&#xff0c;也称为内部变量。它们只在定义它们的函数内部有效&#xff0c;即只有在这个函数被调用时&#xff0c;局部变量才会被分配内存空间&#x…

Java学习【深入解读File类:从基础到高级的完整指南】

Java学习【深入解读File类&#xff1a;从基础到高级的完整指南】 ⭐File的概述和构造方法⭐File常见的成员方法&#x1f319;构造方法&#x1f319;length()&#x1f319;getAbsoluteFile()和getPath()&#x1f319;getName()和lastModified() ⭐文件的创建和删除⭐获取并遍历 …

从 0 打造私有知识库 RAG Benchmark 完整实践

背景介绍 最近从 0 构建了一个大模型知识库 RAG 服务的自动化 Benchmark 评估服务&#xff0c;可以基于私有知识库对 RAG 服务进行批量自动化测试与评估。本文是对这个过程的详细记录。 本文实际构建的是医疗行业知识库&#xff0c;基于高质量的医学指南和专家共识进行构建。…

8K Stars!Text2SQL还不够?试试更精准的RAG2SQL开源工具

▼618钜惠专场直播&#xff0c;点击预约按钮免费预约。 SQL 是查询数据库的关键&#xff0c;但如何高效地构建满足个人需求的 SQL 语句呢&#xff1f;随着 AI 大模型的进步&#xff0c;我们现在已经拥有了 Text2SQL 的技术&#xff0c;这一技术已被多款产品广泛应用。 今天&…

考研数学|做完《660》,做《880》还是吃力,怎么办?

880吃力说明基础还是不太扎实&#xff0c;建议配合知能行再刷880。 强化之前做660&#xff0c;然后在强化的时候再做880。 660整体难度属于基础阶段到强化阶段。而且是选填部分的题目&#xff0c;所以还是要做一些其他题 然后说一下推荐的习题册&#xff1a;基础不好先做1800、…

如何学习 Java 中的 Socket 编程,进行网络通信

Socket编程是网络编程的核心技术之一&#xff0c;它使得不同主机之间可以进行数据通信。Java提供了丰富的网络编程API&#xff0c;使得编写网络应用程序变得相对简单和直观。本文将详细讲解如何学习Java中的Socket编程&#xff0c;并通过示例代码展示如何实现网络通信。 一、S…

船舶能源新纪元:智能管理引领绿色航运潮流

在蓝色的大海上&#xff0c;无数船只乘风破浪&#xff0c;为全球的贸易和文化交流贡献着力量。然而&#xff0c;随着环保意识的提升和可持续发展的要求&#xff0c;船舶的能源消耗和排放问题逐渐成为了人们关注的焦点。在这个关键时刻&#xff0c;船舶能源管理系统应运而生&…

智能合约开发的过程

智能合约是一种运行在区块链上的程序&#xff0c;可以自动执行预先设定的条款和条件。智能合约具有去中心化、透明、不可篡改等特点&#xff0c;因此被广泛应用于金融、供应链、物联网等领域。北京木奇移动技术有限公司&#xff0c;专业的软件外包开发公司&#xff0c;欢迎交流…

西门子学习笔记12 - BYTE-REAL互相转化

这是针对于前面MQTT协议的接收和发送数组只能是BYTE数组做出的对应的功能块封装。 1、BYTE-REAL转化 1、把byte数组转成字符串形式 2、把字符串转成浮点数 2、REAL-BYTE转化 1、把浮点数转成字符串 2、把字符串转成Byte数组

通过编辑器工具改变Inspector锁定状态

是在看一系列视频的时候&#xff0c;看到的&#xff0c;感觉挺有用&#xff0c;就记录下来。 就是这个小锁的按钮&#xff0c;后续可以通过快捷键&#xff0c;快速锁定和解锁。代码里没有加入快捷键控制&#xff0c;有需要用到的可以自己加一下&#xff0c;比较简单 using Uni…

前端上传minio

参考【GitCode - 全球开发者的开源社区,开源代码托管平台】 注意事项&#xff1a;nodejs服务&#xff0c;文件扩展名为mjs&#xff0c;版本号8.0&#xff0c;引入的时候 import * as Minio from minio import Minio as * from minio// 实例化对象存储服务的MinIO客户端 // p…

c语言字符串函数详解(全)

字符串函数 1.strlen函数 求字符串长度的 //求字符串长度 int my_strlen(char* str) {int count 0;while (*str ! \0){count;*str;}return count; } int main() {char arr[] "abcdef";int red my_strlen(arr);printf("%d\n", red);return 0; } 2. st…

【MySQL】(基础篇十二) —— 子查询

分组数据 本文介绍什么是子查询以及如何使用它们。 SQL允许我们创建子查询&#xff08;subquery&#xff09;&#xff0c;即嵌套在其他查询中的查询。这样可以实现更复杂的查询&#xff0c;理解这个概念的最好方法是考察几个例子。 利用子查询进行过滤 需求&#xff1a;查询…