简单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;
}

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

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

相关文章

双指针-旋转链表

目录 一、问题描述 二、解题思路 三、代码实现 四、刷题链接 一、问题描述 二、解题思路 1.先确定链表长度为len 2.注意当K>len时&#xff0c;如果每个节点都往右移动len个位置&#xff0c;等价于不移动&#xff0c;所以需要求KK%len。 3.所有元素右移K个位置&#xf…

uniapp运行到小程序Vue.use注册全局组件不起作用

真想吐槽一下小程序&#xff0c;uniapp运行到小程序使用Vue.use注册全局组件根本不起作用&#xff0c;也不报错&#xff0c;这只是其中一个问题&#xff0c;其他还有很多问题&#xff0c;比如vue中正常使用的没问题的语法&#xff0c;运行到小程序就不行&#xff0c;又是包太大…

【Python机器学习】自动化特征选择——单变量统计

添加更多特征会使所有的模型变得更加复杂&#xff0c;从而增大过拟合的可能性。 在添加新特征或处理一般的高位数据集时&#xff0c;最好将特征的数量减少到只包含最有用的那些特征&#xff0c;并删除其余特征&#xff0c;这样会得到泛化能力更好、更简单的模型。 对于如何判…

生成式人工智能和机器人技术是否即将取得最后的突破?

了解生成式人工智能与机器人技术的融合如何彻底改变从医疗保健到娱乐等行业 想象一下这样一个世界&#xff0c;机器人可以谱写交响乐、画出杰作、写出小说。这种创造力与自动化的迷人融合&#xff0c;由 生成式人工智能&#xff0c;不再是梦想&#xff1b;它正在以重大方式重塑…

1Panel开源面板项目GitHub Star数量突破20,000!

截至2024年6月25日9:00&#xff0c;FIT2CLOUD飞致云旗下开源项目——1Panel开源Linux服务器运维管理面板GitHub Star数超过20,000个&#xff01; 继Halo和JumpServer之后&#xff0c;1Panel成为飞致云旗下第三个GitHub Star数量超过20,000个的开源项目&#xff0c;也是飞致云旗…

Python 类

文章目录 定义类与对象成员方法构造方法魔术方法私有成员继承复写父类成员调用父类成员 多态 定义 class 类名:成员变量成员方法变量类名()# 创建对象 变量.成员变量# 使用成员变量 变量.成员方法类与对象 类相当于设计图纸&#xff0c;规定了各种属性与行为。 对象也就是按照…

(单机架设教程)3D剑踪

前言 今天给大家带来一款单机游戏的架设&#xff1a;3D剑踪 如今市面上的资源参差不齐&#xff0c;大部分的都不能运行&#xff0c;本人亲自测试&#xff0c;运行视频如下&#xff1a; 3D剑踪 搭建教程 此游戏架设不需要虚拟机&#xff0c; 我们先解压 “3D剑踪.zip” &…

【Python】pycharm常用快捷键操作

目录 一.pycharm自定义修改快捷键 二.pycharm默认常用快捷键 一.pycharm自定义修改快捷键 在file-setting-keymap中可以修改快捷键&#xff0c;建议刚开始没特殊需求就不用修改&#xff0c;先熟悉系统默认的常用快捷键&#xff0c;但是以下情况可以考虑修改: 之前使用其他I…

因果解耦表征 | (香港理工ICLR24)联合学习个性化因果不变表示以应对异构联邦客户端

原文&#xff1a;Learning Personalized Causally Invariant Representations for Heterogeneous Federated Clients 地址&#xff1a;https://openreview.net/forum?id8FHWkY0SwF 代码&#xff1a;未知 出版&#xff1a;ICLR 2024 机构: 香港理工大学、香港科技大学 解读&…

JAVA期末速成库(12)第十三章

一、习题介绍 第十三章 Check Point&#xff1a;P501 13.3&#xff0c;13.17&#xff0c;13.28&#xff0c;13.29 Programming Exercise&#xff1a;13.1&#xff0c;13.6&#xff0c;13.11 二、习题及答案 Check Point&#xff1a; 13.3 True or false? a. An abst…

Nature Climate Change | 中国科学院地理资源所吴朝阳课题组发表生物多样性调控植被物候的研究成果!

本文首发于“生态学者”微信公众号&#xff01; 植被春季物候对气候变化的响应通常是通过测量其温度敏感性&#xff08;ST&#xff0c;温度每升高1度&#xff0c;植被提前展叶的天数&#xff09;来量化。ST是植被在当地历史气候环境的选择压力下演化形成的最优策略&#xff0c;…

第一百三十四节 Java数据类型教程 - Java int数据类型

Java数据类型教程 - Java int数据类型 int数据类型是32位有符号Java原语数据类型。 int数据类型的变量需要32位内存。 其有效范围为-2,147,483,648至2,147,483,647&#xff08;-231至231 - 1&#xff09;。 此范围中的所有整数称为整数字面量。 例如&#xff0c;10&#xf…

Eclipse 悬浮提示:提升编程效率的利器

Eclipse 悬浮提示:提升编程效率的利器 引言 对于广大开发者而言,Eclipse 是一款功能强大的集成开发环境(IDE)。它不仅支持多种编程语言,还提供了丰富的插件和工具,以帮助开发者提高编程效率和代码质量。在本文中,我们将重点探讨 Eclipse 中的一个实用功能——悬浮提示…

刷算法Leetcode---7(二叉树篇)(前中后序遍历)

前言 本文是跟着代码随想录的栈与队列顺序进行刷题并编写的 代码随想录 好久没刷算法了&#xff0c;最近又开始继续刷&#xff0c;果然还是要坚持。 二叉树的题目比之前多了好多&#xff0c;就多分几次写啦~ 这是力扣刷算法的其他文章链接&#xff1a;刷算法Leetcode文章汇总 …

PyTorch读写模型(state_dict、torch.save、torch.load)

1. state_dict 在PyTorch中&#xff0c;state_dict 是一个简单的python的字典对象&#xff0c;将每一层与它的对应参数建立映射关系。(如model的每一层的weights及bias等) 首先&#xff0c;我们来定义一个MLP模型&#xff1a; import torch.nn as nnclass MLP(nn.Module):de…

494. 目标和 Medium

给你一个非负整数数组 nums 和一个整数 target 。 向数组中的每个整数前添加 或 - &#xff0c;然后串联起所有整数&#xff0c;可以构造一个 表达式 &#xff1a; 例如&#xff0c;nums [2, 1] &#xff0c;可以在 2 之前添加 &#xff0c;在 1 之前添加 - &#xff0c;然…

使用Calendar.add进行日期计算

使用Calendar.add进行日期计算 大家好&#xff0c;我是免费搭建查券返利机器人省钱赚佣金就用微赚淘客系统3.0的小编&#xff0c;也是冬天不穿秋裤&#xff0c;天冷也要风度的程序猿&#xff01;今天我们将深入探讨在Java中如何使用Calendar.add方法进行日期计算。Calendar类是…

如何在Ubuntu20上离线安装joern(包括sbt和scala)

在Ubuntu 20上离线安装Joern&#xff0c;由于Joern通常需要通过互联网从其官方源或GitHub等地方下载&#xff0c;但在离线环境中&#xff0c;我们需要通过一些额外的步骤来准备和安装。&#xff08;本人水平有限&#xff0c;希望得到大家的指正&#xff09; 我们首先要做的就是…

在QGIS中调用天地图

2019年 1月 1日起&#xff0c;天地图 API及服务接口调用需要获得开发授权&#xff0c;之前使用 QGIS等 GIS软件无法继续调用天地图&#xff0c;这就需要申请一个许可。 一、注册并申请 Key 具体申请可以登录如下地址&#xff1a;https://www.tianditu.gov.cn打开上述网址后点…

速盾:cdn加速哪个好?

在现代互联网时代&#xff0c;网站的速度和稳定性是非常重要的。为了提供最佳的用户体验&#xff0c;许多网站和应用程序都使用CDN&#xff08;内容分发网络&#xff09;来加速其内容的传输。CDN是由位于全球各地的分布式服务器组成的网络&#xff0c;其目的是将内容尽可能快地…