【Linux】手把手教你制作一个简易shell——(进程创建fork进程替换wait与进程等待exec的应用)(自定义shell程序设计)

前言

大家好吖,欢迎来到 YY 滴Linux系列 ,热烈欢迎! 本章主要内容面向接触过C++ Linux的老铁
主要内容含:
在这里插入图片描述

欢迎订阅 YY滴C++专栏!更多干货持续更新!以下是传送门!

  • YY的《C++》专栏
  • YY的《C++11》专栏
  • YY的《Linux》专栏
  • YY的《数据结构》专栏
  • YY的《C语言基础》专栏
  • YY的《初学者易错点》专栏
  • YY的《小小知识点》专栏
  • YY的《单片机期末速过》专栏
  • YY的《C++期末速过》专栏
  • YY的《单片机》专栏
  • YY的《STM32》专栏
  • YY的《数据库》专栏
  • YY的《数据库原理》专栏

目录

  • 一.前置知识
    • 【1】Shell和Bash简述
    • 【2】Bash的输入原理——指针数组
  • 二.自定义shell程序设计
    • 【1】<主函数模块>——大体框架
      • 1.程序设计框架
      • 2.程序设计细节
    • 【2】<打印提示符>模块
      • 1.程序设计框架
      • 2.程序设计细节
    • 【3】<分割字符串>模块
      • 1.程序设计框架
      • 2.程序设计细节
    • 【4】<执行对应的命令>模块
      • 1.程序设计框架
      • 2.程序设计细节

一.前置知识

【1】Shell和Bash简述

  • Shell 是一种命令行界面,是用户与系统之间的接口,允许用户执行命令来 管理系统资源、运行程序等
  • Bash 是 Shell 的一种实现,也是目前最流行的 Shell 之一

【2】Bash的输入原理——指针数组

  1. 我们运行Linux时会出现, bash提示符和命令行 ,我们接下来也要实现这两点

  2. 本质是通过 空格 作为分隔符,把一个一个字符串分隔开载入 指针数组中 ;

  3. 在父进程bash进程中,创建一个子进程,环境变量也会传递给子进程,并进行 进程等待wait
    在这里插入图片描述

  4. 在子进程中通过 进程替换exec ,执行 指针数组中 中的命令(通过环境变量)
    在这里插入图片描述

ifn<=0,直接结束省的创建子进程

cd就不行。因为是子进程的cd…

二.自定义shell程序设计

【1】<主函数模块>——大体框架

1.程序设计框架

  • 根据前置知识中的实现原理
    在这里插入图片描述
  • 我们主函数中要有对应模块:
  1. 打印提示符&&获取用户命令字符串获取成功: getUserCommand函数
  2. 分割字符串: commandSplit函数
  3. 执行对应的命令: execute函数

2.程序设计细节

  1. 设置一个命令行获取字符数组:usercommand
  2. 设置一个存储———分割usercommand数组后的字符串的地址——的指针数组:argv
#define NUM 1024
#define SIZE 64int main()
{while(1){  //shell要不停跑,死循环char usercommand[NUM];char *argv[SIZE];// 1. 打印提示符&&获取用户命令字符串获取成功int n= getUserCommand(usercommand, sizeof(usercommand));// 2. 分割字符串// "ls -a -l" -> "ls" "-a" "-l"commandSplit(usercommand, argv);// 3. 执行对应的命令execute(argv);}
}

【2】<打印提示符>模块

1.程序设计框架

  • 提示符信息包括:1.HOME 2.USER 3.HOSTNAME
  • 我们将上面3个信息分别封装,在getUserCommand函数中统一打印
  • 我们通过getenv函数可以获取 环境变量的地址,进而打印
    在这里插入图片描述
  • command参数 接收命令行获取 字符数组usercommand
  • num参数 接收 字符数组长度

2.程序设计细节

  1. C语言默认会打开三个输入输出流:stdin键盘 stdout显示器stderr显示器,我们用到stdin获取输入流

  2. 不用scanf,用fget函数的原因:scanf遇到空格停下来,命令行本身就会出现空格。故采用行获取接口fgets
    在这里插入图片描述

  3. command参数 接收命令行获取 字符数组usercommand ,我们输入命令后,最终你还是会输入\n——导致执行结果和shell之间出现空行;所以我们在输入完后要把command最后一个字符'\n'换成'\0'

int getUserCommand(char *command, int num)
{printf("[%s@%s %s]# ", getUsername(), getHostname(), getCwd());char *r = fgets(command, num, stdin); // 最终你还是会输入\nif(r == NULL) return -1;// "abcd\n" "\n"command[strlen(command) - 1] = '\0'; // 有没有可能越界?不会return strlen(command);
}char *homepath()
{char *home = getenv("HOME");if(home) return home;else return (char*)".";
}const char *getUsername()
{const char *name = getenv("USER");if(name) return name;else return "none";
}
const char *getHostname()
{const char *hostname = getenv("HOSTNAME");if(hostname) return hostname;else return "none";
}

【3】<分割字符串>模块

1.程序设计框架

  • 这个模块,我们要通过 空格 作为分隔符,把一个一个字符串分隔开载入 指针数组 argv
  • in参数 接收命令行获取 字符数组usercommand
  • *out[]参数 输出型参数,用于传出 分割usercommand数组后的字符串的地址——的指针数组argv

2.程序设计细节

  • 通过strstok函数分割; 注意语法,分成首次分割,和剩余分割
    在这里插入图片描述
#define SEP " "
void commandSplit(char *in, char *out[])
{int argc = 0;out[argc++] = strtok(in, SEP);while( out[argc++] = strtok(NULL, SEP));
}

【4】<执行对应的命令>模块

1.程序设计框架

我们回顾原理部分:

  • 在父进程bash进程中,创建一个子进程,环境变量也会传递给子进程,并进行 进程等待wait
    在这里插入图片描述

  • 在子进程中通过 进程替换exec ,执行 指针数组中 中的命令(通过环境变量)
    在这里插入图片描述

于是我们设计出:

  1. fork函数创建子进程
  2. 子进程进行进程替换execvp函数,用到 分割usercommand数组后的字符串的地址——的指针数组argv
  3. 父进程等待子进程

2.程序设计细节

1. fork函数:
在这里插入图片描述

2. execvp函数: 由于我们用到了指针数组argv,所以用exec系列的vp尾缀,execvp 表示v(vector)数组,p(可以使用环境变量PATH,无需写全路径)
在这里插入图片描述

3. waitpid函数:不关心后续操作,status参数设置成NULL,options参数设置成0
在这里插入图片描述

int execute(char *argv[])
{pid_t id = fork();if(id < 0) return -1;else if(id == 0) //child{// exec commandexecvp(argv[0], argv); // cd ..exit(1);}else // father{int status = 0;pid_t rid = waitpid(id, NULL, 0);}return 0;
}

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

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

相关文章

HTTP协议:发展、请求响应、状态码 等

文章目录 HTTP发展历程HTTP请求URL和URIHTTP协议版本HTTP请求方法GET 和 POST 区别HTTP状态码HTTP 请求与响应报文HTTP 请求流程 HTTP 超文本传输协议&#xff08;Hypertext Transfer Protocol&#xff0c;HTTP&#xff09;是一个简单的请求-响应协议&#xff0c;它通常运行在…

快速数据检索最佳闪存驱动器恢复下载

当你意识到你的闪存盘丢失了重要文件时&#xff0c;你是否曾有过心脏停跳的时刻&#xff1f;丢失数据可能会毁掉你的一天&#xff0c;并带来很大的压力&#xff0c;无论是重要的工作文件&#xff0c;你喜欢的照片&#xff0c;还是备份你需要保持。好消息是&#xff0c;在闪存驱…

Leetcode 合并区间

我们借助一个辅助链表(元素类型是一维数组)来进行结果统计。 这个算法解决了“合并区间”的问题&#xff0c;具体要求是给定一组区间&#xff08;每个区间有开始和结束位置&#xff09;&#xff0c;如果两个区间有重叠&#xff0c;那么需要将它们合并成一个区间&#xff0c;并…

Cisco Packet Tracer超详细下载安装教程(附中文版插件)

一、安装包下载&#xff1a; 链接&#xff1a;https://pan.baidu.com/s/1RK8iQ9lJG__vBEGCYVYNSA 提取码&#xff1a;1lvb 压缩包解压密码&#xff1a;66668888&#xff0c;不能正常解压的&#xff0c;推荐使用360压缩解压 二、安装教程&#xff1a; 1.双击启动安装包 2.点击N…

使用功率谱密度 (PSD) 表征噪声

传递函数塑造噪声 图 1 显示了假设噪声源的频谱&#xff0c;该噪声源在所有频率下均表现出相同的平均功率&#xff0c;即 &#xff0c;其中 η 是常数。 假设噪声源的频谱。 图 1. 假设噪声源的频谱。 如果我们将此噪声应用于 LTI 系统&#xff0c;系统的传递函数将决定不同…

基于丹摩智算平台-手把手拿下经典目标检测模型 Faster-Rcnn

文章目录 1. 前言1. 1 丹摩智算平台1.2 经典目标检测模型 Faster-Rcnn 2. 前置准备2.1 WindTerm&#xff08;远程连接服务器&#xff09;2.2 项目源码 3. 服务器平台配置3.1 创建实例3.2 远程链接 4. Faster-rcnn 的环境配置4.1 上传文件&#xff0c;解压4.2 安装所需环境 5. 数…

springboot框架VUE3学院网站系统开发mysql数据库设计java编程计算机网页源码maven项目

博主介绍&#xff1a;专注于Java vue .net php phython 小程序 等诸多技术领域和毕业项目实战、企业信息化系统建设&#xff0c;从业十五余年开发设计教学工作 ☆☆☆ 精彩专栏推荐订阅☆☆☆☆☆不然下次找不到哟 我的博客空间发布了1000毕设题目 方便大家学习使用 感兴趣的…

专业软件测试服务机构介绍:软件确认测试的类型和方法

随着现代科技的迅猛发展&#xff0c;软件开发逐渐成为各类企业发展的核心。然而&#xff0c;软件的质量直接关系到企业的运营效率和用户体验。因此&#xff0c;软件确认测试作为确保软件质量的重要环节&#xff0c;正受到越来越多的关注。 软件确认测试是指在软件开发周期的最…

tensorboard展示不同运行的曲线结果

运行tensorboard曲线如下&#xff1a; tensorboard --logdir .有时候&#xff0c;曲线图会展示多条曲线&#xff0c;以至于我们想分辨哪条线来自哪次训练都做不到了。如下图是设置smoothing-0.6的结果&#xff1a; smoothing可以在页面找到设置按钮&#xff0c;呼出设置侧边…

Llama 3.1 技术研究报告-2

3.3 基础设施、扩展性和效率 我们描述了⽀持Llama 3 405B⼤规模预训练的硬件和基础设施&#xff0c;并讨论了⼏项优化措施&#xff0c;这些措施提⾼了训练效率。 3.3.1 训练基础设施 Llama 1和2模型在Meta的AI研究超级集群&#xff08;Lee和Sengupta&#xff0c;2022&#x…

直播美颜工具的开发详解:基于视频美颜SDK的解决方案

视频美颜SDK的出现&#xff0c;为开发直播美颜工具提供了一种高效的解决方案。本文将详细解析如何基于视频美颜SDK&#xff0c;开发一款性能优越、功能齐全的直播美颜工具。 1.视频美颜SDK的核心功能 视频美颜SDK是实现实时美颜的关键技术&#xff0c;其核心功能包括人脸检测、…

mysql逗号分隔的一行数据转为多行数据

原表&#xff1a; 结果&#xff1a; 方法一&#xff1a;如果每条数据的被逗号分隔的数量在637条以内&#xff0c;使用 mysql.help_topic&#xff08;mysql自带的表&#xff0c;只有637个序号&#xff09;。 select a.id,a.enclosure_ids,SUBSTRING_INDEX(SUBSTRING_INDEX(a.en…

harmonyOS 原来构建还有这么多弯弯绕绕

随着用户需求的不断增长&#xff0c;我们的 APP 已发展成功能丰富的超级APP&#xff0c;这也导致打包构建变得非常耗时&#xff0c;可能需要数小时&#xff0c;严重影响开发效率和产品迭代。通过采用模块化设计、增量构建、并行处理、缓存机制、优化依赖管理&#xff0c;以及云…

使用 Docker 部署 RStudio 的终极教程

一.介绍 在现代数据科学和统计分析领域&#xff0c;RStudio 是一个广受欢迎的集成开发环境&#xff08;IDE&#xff09;&#xff0c;为用户提供了强大的工具来编写、调试和可视化 R 代码。然而&#xff0c;传统的 RStudio 安装可能面临环境配置复杂、版本兼容性等问题。Docker…

2.4K star的GOT-OCR2.0:端到端OCR 模型

GOT-OCR2.0是一款新一代的光学字符识别&#xff08;OCR&#xff09;技术&#xff0c;标志着人工智能在文本识别领域的重大进步。作为一款开源模型&#xff0c;GOT-OCR2.0不仅支持传统的文本和文档识别&#xff0c;还能够处理乐谱、图表以及复杂的数学公式&#xff0c;为用户提供…

报错解决方案

大模型-报错解决方案 百度千帆大模型 仅个人笔记使用&#xff0c;感谢点赞关注 百度千帆大模型 未开通付费模型 qianfan.errors.APIError: api return error, req_id: code: 17, msg: Open api daily request limit reached 可能的原因: 未开通所调用服务的付费权限&#xff0…

代码随想录算法day38 | 动态规划算法part11 | 1143.最长公共子序列,1035.不相交的线,53. 最大子序和,392.判断子序列

1143.最长公共子序列 体会一下本题和 718. 最长重复子数组 的区别 力扣题目链接(opens new window) 给定两个字符串 text1 和 text2&#xff0c;返回这两个字符串的最长公共子序列的长度。 一个字符串的 子序列 是指这样一个新的字符串&#xff1a;它是由原字符串在不改变字符的…

掌握Python自动化办公的3个核心技能,全是干货建议收藏

随着Python在办公自动化领域的广泛应用&#xff0c;掌握Python的相关技能变得越来越重要。本文将详细介绍Python在文件操作、数据处理以及Excel操作方面的核心技能&#xff0c;帮助读者提升工作效率。 掌握Python自动化办公的核心技能&#xff0c;主要包括以下几个方面&#x…

统信服务器操作系统进入【单用户模式】

统信服务器操作系统D版、E版、A版进入单用户模式的方式。 文章目录 前言一、问题现象二、问题原因三、解决方案1. D版问题解决方案2. E版及A版问题解决方案前言 D版又称企业版、E版又称欧拉版、A版又称龙蜥版。 单用户模式主要是在 grub2 引导时编辑内核引导,一般用于修改用…

828华为云征文 | 云服务器Flexus X实例,搭建ChatGpt:AI-OpenAI

828华为云征文 | 云服务器Flexus X实例&#xff0c;搭建ChatGpt&#xff1a;AI-OpenAI 搭建能AI-OpenAI 1、购买华为云 Flexus X 实例 Flexus云服务器X实例-华为云 (huaweicloud.com) 2、安装 Docker 的必要依赖 yum install -y yum-utils device-mapper-persistent-data lvm2…