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

简单shell

目录

预备知识

fork

进程等待

wait

waitpid

环境变量

概念

分类

常见的环境变量及其用途

环境变量的查看与设置

exec系列

 函数解释

命名理解

简单shell


预备知识

fork

fork 是 Linux 和许多其他类 Unix 系统中的一个重要系统调用,它用于创建一个新的进程,这个新进程是当前进程的复制品,称为子进程。子进程会获得父进程当前状态的副本,包括父进程的内存布局、环境变量、打开的文件描述符等。但是,子进程和父进程是两个独立的执行线程,它们可以独立地运行程序的不同部分。

以下是关于 fork 的一些关键点:

  1. 复制:子进程是父进程的一个副本。但是,这种复制是“写时复制”(Copy-On-Write, COW)的。这意味着,如果子进程和父进程都不修改它们共享的内存区域,那么这些区域实际上不会被复制,从而节省内存和 CPU 时间。
  2. 返回值fork 系统调用在父进程中返回新创建的子进程的进程 ID(PID),而在子进程中返回 0。这是区分父进程和子进程的一个常用方法。
  3. 资源分配:子进程会获得其父进程所拥有资源的副本,如文件描述符、环境变量等。但是,这些资源并不一定是物理上独立的;它们通常是通过引用计数或其他机制来共享的。
  4. 并发:由于子进程和父进程是两个独立的执行线程,因此它们可以并发地执行不同的任务。这使得 fork 成为实现多进程并发和并行处理的重要工具。
  5. 进程间通信:由于子进程和父进程是独立的,因此它们之间需要进行通信以共享数据或协调行为。这可以通过各种进程间通信(IPC)机制来实现,如管道、消息队列、信号量、共享内存等。
  6. 终止和等待:当子进程终止时,它会留下一个僵尸进程(Zombie Process),直到其父进程调用 wait 或 waitpid 系统调用来获取其终止状态并释放其占用的资源。

需要注意的是,虽然 fork 是一个强大的工具,但它也有一些限制和开销。例如,由于需要复制父进程的状态,因此 fork 的开销通常比创建线程要大。此外,由于子进程和父进程是独立的,因此它们之间的通信和同步也需要额外的开销和复杂性。因此,在选择使用 fork 还是其他并发机制(如线程或协程)时,需要根据具体的应用场景和需求进行权衡。

进程等待

wait

  • 功能wait函数用于使父进程等待其任意一个子进程结束,并回收该子进程的资源。当子进程结束时,内核会向父进程发送SIGCHLD信号,父进程可以通过wait函数来响应这个信号并获取子进程的状态。
  • 函数原型pid_t wait(int *wstatus);
    • 参数wstatus是一个指向整数的指针,用于存储子进程的退出状态。如果父进程不关心子进程的退出状态,可以将此参数设为NULL。
    • 返回值是已结束子进程的进程ID(PID),如果出现错误则返回-1。
  • 特点wait函数会阻塞父进程的执行,直到有一个子进程结束。如果调用wait时子进程已经结束,则wait会立即返回子进程的结束状态值。

waitpid

  • 函数原型:#include #include pid_t wait(int*status); 返回值: 成功返回被等待进程pid,失败返回-1
  • 返回值:
    • 当正常返回的时候waitpid返回收集到的子进程的进程ID;
    • 如果设置了选项WNOHANG,而调用中waitpid发现没有已退出的子进程可收集,则返回0;
    • 如果调用中出错,则返回-1,这时errno会被设置成相应的值以指示错误所在;
  • 参数:
    • pid:
      • Pid=-1,等待任一个子进程。与wait等效。
      • Pid>0.等待其进程ID与pid相等的子进程。
    • status:
      • WIFEXITED(status): 若为正常终止子进程返回的状态,则为真。(查看进程是否是正常退出)
      • WEXITSTATUS(status): 若WIFEXITED非零,提取子进程退出码。(查看进程的退出码)
    • options:
      • WNOHANG: 若pid指定的子进程没有结束,则waitpid()函数返回0,不予以等待。若正常结束,则返回该子进 程的ID。

环境变量

概念

  • 定义:环境变量是系统预定义的参数,相当于全局变量,存在于所有的shell中,具有继承性。它们可存储有关shell会话和工作环境的信息。
  • 作用:环境变量允许在内存中存储数据,以便运行在shell上的程序和脚本访问。这些数据可以用来识别用户、系统、Shell的特性以及任何其它需要存储的数据。

分类

  • 按作用范围分
    • 系统环境变量:公共的,对全部的用户都生效。
    • 用户环境变量:用户私有的、自定义的个性化设置,只对该用户生效。
  • 按生存周期分
    • 永久环境变量:在环境变量脚本文件中配置,用户每次登录时会自动执行这些脚本,相当于永久生效。
    • 临时环境变量:使用时在Shell中临时定义,退出Shell后失效。

常见的环境变量及其用途

  • PATH:指定命令的搜索路径,由冒号分隔的目录列表,用于告诉系统在哪里可以找到可执行文件。
  • HOME:指定用户的主工作目录,即用户登录到Linux系统时,默认的目录。
  • SHELL:当前Shell的路径,通常指向用户当前使用的shell解析器,如/bin/bash
  • LD_LIBRARY_PATH:C/C++语言动态链接库文件搜索的目录,对C/C++程序员来说非常重要。
  • CLASSPATH:JAVA语言库文件搜索的目录,对JAVA程序员来说非常重要。

环境变量的查看与设置

  • 查看
    • 使用env命令可以查看当前用户全部的环境变量。
    • 使用echo $环境变量名可以查看特定环境变量的值。
  • 设置
    • 使用export命令可以设置新的环境变量或修改现有环境变量的值。例如,export PATH=$PATH:/new/directory
    • 如果希望环境变量永久生效,需要在登录脚本文件中(如/etc/profile/etc/profile.d/~/.bash_profile~/.bashrc等)进行配置

exec系列

#include <unistd.h>

int execl(const char *path, const char *arg, ...);

int execlp(const char *file, const char *arg, ...);

nt execle(const char *path, const char *arg, ...,char *const envp[]);

int execv(const char *path, char *const argv[]); i

nt execvp(const char *file, char *const argv[]);

int execve(const char *path, char *const argv[], char *const envp[]);

这些函数的主要目的是在当前进程的上下文中执行一个新程序,从而替换当前进程的映像。它们允许程序在运行时加载新的可执行文件,实现动态性和灵活性。

 函数解释

  • 这些函数如果调用成功则加载新的程序从启动代码开始执行,不再返回。
  • 如果调用出错则返回-1
  • 所以exec函数只有出错的返回值而没有成功的返回值

命名理解

  • l(list) : 表示参数采用列表
  •  v(vector) : 参数用数组
  • p(path) : 有p自动搜索环境变量PATH
  • e(env) : 表示自己维护环境变量

简单shell

#include<stdio.h>
#include<stdlib.h>
#include<string.h>
#include<ctype.h>
#include<unistd.h>
#include<fcntl.h>
#include<errno.h>
#include<sys/wait.h>
#define SIZE 512
#define ZERO '\0'
#define SEP " "
#define NUM 32
#define SkipPath(p) do{p+=strlen(p)-1;while(*p!='/')p--;}while(0)
#define SkipSpace(cmd,pos) do{ \while(1){\if(isspace(cmd[pos]))\pos++;\else break;\}}while(0)
#define none_type 0
#define in_type 1
#define out_type 2
#define app_type 3
int redir_type=none_type;
char* filename=NULL;char* gArgv[NUM];
int lastcode=0;
void Die()
{exit(1);
}
const char* GetHostname()
{const char* hostname=getenv("HOSTNAME");if(hostname==NULL)return "/";return hostname;
}
const char* GetUsername()
{const char* user=getenv("USER");if(user==NULL)return "none";return user;
}
const char* Getcwd()
{const char* cwd=getenv("PWD");if(cwd==NULL) return "none";return cwd;
}
void MakeCommmandLine()
{char line[SIZE];const char* hostname=GetHostname();const char* username=GetUsername();const char* cwd=Getcwd();SkipPath(cwd);snprintf(line,sizeof(line),"[%s@%s %s]> ",username,hostname,strlen(cwd)==1?"/":cwd+1);printf("%s",line);fflush(stdout);
}
int GetUserCommad(char commad[],size_t n)
{char* s=fgets(commad,n,stdin);if(s==NULL)return -1;commad[strlen(commad)-1]=ZERO;return strlen(commad);}
void CheckRedir(char cmd[])
{int pos=0;int end=strlen(cmd);while(pos<end){if(cmd[pos]=='>'){if(cmd[pos+1]=='>'){cmd[pos++]=0;pos++;redir_type=app_type;SkipSpace(cmd,pos);filename=cmd+pos;}else {cmd[pos++]=0;redir_type=out_type;SkipSpace(cmd,pos);filename=cmd+pos;  }}else if(cmd[pos]=='<'){cmd[pos++]=0;redir_type=in_type;SkipSpace(cmd,pos);filename=cmd+pos;}else{pos++;}}
}
void SplitCommad(char command[])
{gArgv[0]=strtok(command,SEP);int index=1;while((gArgv[index++]=strtok(NULL,SEP)));
}
void ExecuteCommand()
{pid_t id=fork();if(id<0)Die();else if (id==0){//子进程if(filename!=NULL){if(redir_type==in_type){int fd=open(filename,O_RDONLY);dup2(fd,0);}else if (redir_type==out_type){int fd = open(filename, O_WRONLY | O_CREAT | O_TRUNC, 0666);dup2(fd, 1); }else if (redir_type==app_type){int fd = open(filename, O_WRONLY | O_CREAT | O_APPEND, 0666);dup2(fd, 1);}}execvp(gArgv[0],gArgv);exit(errno);}else{//父进程int status = 0;pid_t rid = waitpid(id, &status, 0);if(rid > 0){lastcode = WEXITSTATUS(status);if(lastcode != 0) printf("%s:%s:%d\n", gArgv[0], strerror(lastcode), lastcode);} }
}
int main()
{int quit=0;while(!quit){redir_type=none_type;filename=NULL;//创建一个自己的命令行MakeCommmandLine();//获取用户命令char usercommad[SIZE];int n=GetUserCommad(usercommad,sizeof(usercommad));if(n<=0)return 1;CheckRedir(usercommad);//测试一下//   printf("cmd: %s\n", usercommad);//   printf("redir: %d\n", redir_type);//   printf("filename: %s\n", filename);//分割字符串SplitCommad(usercommad);//执行命令ExecuteCommand();}return 0;
}

相关文章:

简单shell

目录 预备知识 fork 进程等待 wait waitpid 环境变量 概念 分类 常见的环境变量及其用途 环境变量的查看与设置 exec系列 函数解释 命名理解 简单shell 预备知识 fork fork 是 Linux 和许多其他类 Unix 系统中的一个重要系统调用&#xff0c;它用于创建一个新的…...

Spring Boot + FreeMarker 实现动态Word文档导出

Spring Boot FreeMarker 实现动态Word文档导出 在现代企业应用中&#xff0c;文档自动化生成是一项提升工作效率的重要功能。Spring Boot与FreeMarker的组合&#xff0c;为开发者提供了一个强大的平台&#xff0c;可以轻松实现动态Word文档的导出。本文将指导你如何使用Sprin…...

3D生物打印的未来:多材料技术的突破

多材料生物打印技术是近年来发展迅速的一项技术&#xff0c;为组织工程和再生医学带来了新的机遇&#xff0c;可以帮助我们更好地理解人体组织的结构和功能&#xff0c;并开发新的治疗方法。 1. 组织构建 复杂性模拟&#xff1a;多材料生物打印技术能够构建具有层次结构和异质…...

充电宝口碑哪个好?好用充电宝品牌有哪些?好用充电宝推荐

充电宝作为我们日常生活和出行的重要伙伴&#xff0c;其品质和性能直接影响着我们的使用体验。今天&#xff0c;就来和大家探讨一下充电宝口碑哪个好&#xff0c;为大家盘点那些备受赞誉的好用充电宝品牌&#xff0c;并向您推荐几款值得入手的充电宝&#xff0c;外出时不再担心…...

Pytorch-----(6)

一 、问题 如何计算基于不同变量的操作如矩阵乘法。 二、具体实现 0.4版本以前&#xff0c;张量是包裹在变量之中的&#xff0c;后者有三个属性grad、volatile和 requires_grad属性。&#xff08;grad 就是梯度属性&#xff0c;requires_grad属性就是 是否需要存储梯度&#x…...

leetcode hot100 第三题:最长连续序列(Java)

给定一个未排序的整数数组 nums &#xff0c;找出数字连续的最长序列&#xff08;不要求序列元素在原数组中连续&#xff09;的长度。 请你设计并实现时间复杂度为 O(n) 的算法解决此问题。 示例 1&#xff1a; 输入&#xff1a;nums [100,4,200,1,3,2] 输出&#xff1a;4 解…...

利用Jaspar进行转录因子结合位点预测

前期我们介绍了如何进行ChIP-qPCR验证&#xff0c;里面提到了一个比较重要的因素——扩增范围的选择及引物的设计。相比双荧光素酶、酵母单杂-点对点验证等允许完整启动子验证的实验&#xff0c;ChIP-qPCR要求单次验证的范围尽量控制在150-200bp内。但一个基因的启动子一般有2-…...

Ubuntu添加系统字体

&#xff08;2024.6.30&#xff09; 系统字体保存路径在/usr/share/fonts下&#xff0c;如果此目录下缺少字体&#xff0c;则使用其他可视化api&#xff08;如Python的pygame库&#xff09;的默认配置时可能会出现乱码问题。 往Ubuntu中添加字体的方法 方法一&#xff1a;手…...

深度学习相关概念及术语总结2

目录 76.AUC77.DBSCAN聚类78.贝叶斯个性化排序79.BPRBandit算法 76.AUC AUC&#xff08;Area Under the Curve&#xff09;是一种常用的评价指标&#xff0c;用于衡量分类模型的性能。AUC值代表了模型在不同阈值下的真阳性率&#xff08;True Positive Rate&#xff09;和假阳…...

基于改进滑模、经典滑模、最优滑模控制的永磁同步电机调速系统MATLAB仿真

微❤关注“电气仔推送”获得资料&#xff08;专享优惠&#xff09; 模型简介 针对永磁同步电机调速系统的响应性能和抗干扰能力问题&#xff0c;本文做了四个仿真&#xff0c;分别为&#xff1a;永磁同步电机的PID控制调速系统、基于传统滑模控制的永磁同步电机的调速系统、最…...

windows环境下创建python虚拟环境

windows环境下创建python虚拟环境 使用virtualenv库创建虚拟环境&#xff0c;可使不同的项目处于不同的环境中 安装方法&#xff1a; pip install virtualenv -i https://pypi.tuna.tsinghua.edu.cn/simple pip install virtualenvwrapper-win -i https://pypi.tuna.tsinghua…...

Fragment切换没变化?解决办法在这里

大家好&#xff0c;今天跟大家分享下如何避免fragment切换失败。方法其实很简单&#xff0c;只要在onCreate方法中初始化一个默认的fragment即可。 //开始事务FragmentTransaction transaction getActivity().getSupportFragmentManager().beginTransaction();transaction.rep…...

Linux系统防火墙iptables(下)

备份与还原iptables规则设置 1、yum -y install iptables iptables-services 安装iptables软件包 2、systemctl start iptables.service 开启服务 3、systemctl enable iptables.service 开机自启 我们对iptables命令行中的设置&#xff0c;都是临时设置&#xff0c;只要遇到服…...

你需要精益管理咨询公司的N+1个理由

近年来&#xff0c;精益管理作为一种被全球众多知名企业验证过的成功管理模式&#xff0c;越来越受到企业的青睐。但是&#xff0c;为何在实施精益管理的过程中&#xff0c;众多企业纷纷选择请咨询公司来协助呢&#xff1f;今天&#xff0c;我们就来一起揭秘这背后的原因。 1. …...

[机器学习]-3 万字话清从传统神经网络到深度学习

神经网络&#xff08;Neural Networks, NNs&#xff09;是机器学习的一种重要方法&#xff0c;灵感来源于生物神经系统&#xff0c;由大量互联的节点&#xff08;称为神经元或单元&#xff09;组成&#xff0c;通过调整这些节点间的连接权重来学习和表示复杂的非线性关系。传统…...

网络安全等级保护2.0(等保2.0)全面解析

一、等保2.0的定义和背景 网络安全等级保护2.0&#xff08;简称“等保2.0”&#xff09;是我国网络安全领域的基本制度、基本策略、基本方法。它是在《中华人民共和国网络安全法》指导下&#xff0c;对我国网络安全等级保护制度进行的重大升级。等保2.0的发布与实施&#xff0c…...

用Lobe Chat部署本地化, 搭建AI聊天机器人

Lobe Chat可以关联多个模型&#xff0c;可以调用外部OpenAI, gemini,通义千问等, 也可以关联内部本地大模型Ollama, 可以当作聊天对话框消息框来集成使用 安装方法参考&#xff1a; https://github.com/lobehub/lobe-chat https://lobehub.com/zh/docs/self-hosting/platform/…...

基于ARM的通用的Qt移植思路

文章目录 实验环境介绍一、确认Qt版本二、确认交叉编译工具链三、配置Qt3.1、修改qmake.conf3.2、创建autoConfig.sh配置文件 四、编译安装Qt五、移植Qt安装目录六、配置Qt creator6.1、配置qmake6.2、配置GCC编译器6.3、配置G编译器6.4、配置编译器套件6.5、创建应用 七、总结…...

IT专业入门,高考假期预习指南

七月来临&#xff0c;各省高考分数已揭榜完成。而高考的完结并不意味着学习的结束&#xff0c;而是新旅程的开始。对于有志于踏入IT领域的高考少年们&#xff0c;这个假期是开启探索IT世界的绝佳时机。 一、基础课程预习指南 IT专业是一个广泛的领域&#xff0c;涵盖了从软件开…...

芯片详解——AD7606C

芯片详解——AD7606C AD7607C 是一款由 Analog Devices(模拟器件公司)生产的 6 通道同步采样模数转换器(ADC),适用于高速数据采集系统。 工作原理 AD7607C 的工作原理主要包括以下几个步骤: 模拟信号输入:AD7607C 有六个模拟输入通道,可以同时进行采样。这些模拟信号…...

在鸿蒙HarmonyOS 5中实现抖音风格的点赞功能

下面我将详细介绍如何使用HarmonyOS SDK在HarmonyOS 5中实现类似抖音的点赞功能&#xff0c;包括动画效果、数据同步和交互优化。 1. 基础点赞功能实现 1.1 创建数据模型 // VideoModel.ets export class VideoModel {id: string "";title: string ""…...

Qt Http Server模块功能及架构

Qt Http Server 是 Qt 6.0 中引入的一个新模块&#xff0c;它提供了一个轻量级的 HTTP 服务器实现&#xff0c;主要用于构建基于 HTTP 的应用程序和服务。 功能介绍&#xff1a; 主要功能 HTTP服务器功能&#xff1a; 支持 HTTP/1.1 协议 简单的请求/响应处理模型 支持 GET…...

在Ubuntu中设置开机自动运行(sudo)指令的指南

在Ubuntu系统中&#xff0c;有时需要在系统启动时自动执行某些命令&#xff0c;特别是需要 sudo权限的指令。为了实现这一功能&#xff0c;可以使用多种方法&#xff0c;包括编写Systemd服务、配置 rc.local文件或使用 cron任务计划。本文将详细介绍这些方法&#xff0c;并提供…...

HTML前端开发:JavaScript 常用事件详解

作为前端开发的核心&#xff0c;JavaScript 事件是用户与网页交互的基础。以下是常见事件的详细说明和用法示例&#xff1a; 1. onclick - 点击事件 当元素被单击时触发&#xff08;左键点击&#xff09; button.onclick function() {alert("按钮被点击了&#xff01;&…...

C++八股 —— 单例模式

文章目录 1. 基本概念2. 设计要点3. 实现方式4. 详解懒汉模式 1. 基本概念 线程安全&#xff08;Thread Safety&#xff09; 线程安全是指在多线程环境下&#xff0c;某个函数、类或代码片段能够被多个线程同时调用时&#xff0c;仍能保证数据的一致性和逻辑的正确性&#xf…...

Maven 概述、安装、配置、仓库、私服详解

目录 1、Maven 概述 1.1 Maven 的定义 1.2 Maven 解决的问题 1.3 Maven 的核心特性与优势 2、Maven 安装 2.1 下载 Maven 2.2 安装配置 Maven 2.3 测试安装 2.4 修改 Maven 本地仓库的默认路径 3、Maven 配置 3.1 配置本地仓库 3.2 配置 JDK 3.3 IDEA 配置本地 Ma…...

【数据分析】R版IntelliGenes用于生物标志物发现的可解释机器学习

禁止商业或二改转载&#xff0c;仅供自学使用&#xff0c;侵权必究&#xff0c;如需截取部分内容请后台联系作者! 文章目录 介绍流程步骤1. 输入数据2. 特征选择3. 模型训练4. I-Genes 评分计算5. 输出结果 IntelliGenesR 安装包1. 特征选择2. 模型训练和评估3. I-Genes 评分计…...

C++ 设计模式 《小明的奶茶加料风波》

&#x1f468;‍&#x1f393; 模式名称&#xff1a;装饰器模式&#xff08;Decorator Pattern&#xff09; &#x1f466; 小明最近上线了校园奶茶配送功能&#xff0c;业务火爆&#xff0c;大家都在加料&#xff1a; 有的同学要加波霸 &#x1f7e4;&#xff0c;有的要加椰果…...

淘宝扭蛋机小程序系统开发:打造互动性强的购物平台

淘宝扭蛋机小程序系统的开发&#xff0c;旨在打造一个互动性强的购物平台&#xff0c;让用户在购物的同时&#xff0c;能够享受到更多的乐趣和惊喜。 淘宝扭蛋机小程序系统拥有丰富的互动功能。用户可以通过虚拟摇杆操作扭蛋机&#xff0c;实现旋转、抽拉等动作&#xff0c;增…...

如何应对敏捷转型中的团队阻力

应对敏捷转型中的团队阻力需要明确沟通敏捷转型目的、提升团队参与感、提供充分的培训与支持、逐步推进敏捷实践、建立清晰的奖励和反馈机制。其中&#xff0c;明确沟通敏捷转型目的尤为关键&#xff0c;团队成员只有清晰理解转型背后的原因和利益&#xff0c;才能降低对变化的…...