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

Linux进程概念(四)环境地址变量

我们先来思考几个问题

1.为什么函数返回值,会被外部拿到呢?函数里面定义的不都是局部变量吗

2.系统如何得知我们的进程当前执行到哪行代码了?

第一个问题,函数在return a时,会直接编译成mov eax 10,会将a的值放到寄存器当中。所以函数返回值是通过寄存器拿到外部的。

第二个问题 cpu内部有个程序计数器(pc,eip),他会记录当前进程正在执行指令的下一行指令的地址。cpu内寄存器里面保存的都是进程相关的数据。

进程在从cpu上离开的时候,要将自己的上下文数据保存好,甚至带走。保存的目的,未来都是为了恢复。所以进程在切换的时候:

1.保存上下文。

2.恢复上下文。

那么cpu上的临时数据应该保存在哪里比较好。

我们知道可执行程序本质上就是指令,为什么我们自己创建的可执行程序需要./才能够被执行,而系统指令例如ls等可以直接被运行。

基本概念

环境变量(environment variables)一般是指在操作系统中用来指定操作系统运行环境的一些参数 如:我们在编写C/C++代码的时候,在链接的时候,从来不知道我们的所链接的动态静态库在哪里,但是照样可以链接成功,生成可执行程序,原因就是有相关环境变量帮助编译器进行查找。 环境变量通常具有某些特殊用途,还有在系统当中通常具有全局特性

常见环境变量

PATH : 指定命令的搜索路径

HOME : 指定用户的主工作目录(即用户登陆到Linux系统中时,默认的目录)

SHELL : 当前Shell,它的值通常是/bin/bash。

PATH:

我们知道可执行程序本质上就是指令,为什么我们自己创建的可执行程序需要./才能够被执行,而系统指令例如ls等可以直接被运行。

操作系统怎么知道ls在哪里呢,因为操作系统在执行ls命令时候,shell会在PATH一个路径一个路径

下去找,找到对应的ls后会直接执行对应路径下的ls程序。

而mycmd不在系统默认的指令搜索路径下,所以在直接执行mycmd时找不到这个指令,会有“command not found”。所以PATH时linux下的指令搜索路径,输入指令时会在PATH中查找。

./的目的是告诉Linux我们要执行的指令mycmd对应的可执行程序就在当前路径,执行对应的可执行程序的时候不要去PATH环境变量中的路径去找对应指令的可执行程序了,而是去当前路径下去找可执行程序mycmd去运行

如果把我当前所处的路径放到PATH环境变量中,自己写的程序是否就可以不用./而可以直接像指令一样去运行呢?

我们先将当前路径加到PATH中

我们再执行mycmd

发现此时mycmd可以像系统指令一样不需要./就可以直接被运行

查看环境变量方法 echo $环境变量名

环境变量是系统提供的一组name=value形式的变量,不同的环境变量有不同的用户,通常具有全局属性。

env显示所有环境变量

/dev/pts/0字符设备

我们复制ssh渠道,在复制的ssh渠道上输入hello显示在复制的ssh渠道中,那么如果我们想要将其显示在当前原ssh渠道,那么可以使用echo>重定向到原ssh渠道的字符设备上进行显示

HISTSIZE默认保存的历史指令条数

我们使用方向键中“上”,可以不断查看上一次输入的指令,那么在linux中一定是有专门的文件存储,这些指令的默认上限是1000,即linux会默认保存1000条之前在命令行中输入的指令。

OLDPWD保存上一次所处路径

OLDPWD是将上一次所处路径进行保存,因为cd-的作用可以返回上一次路径,所以就一定会将上一次路径进行保存。

getenv通过系统调用获取环境变量

输入要获取的环境变量名,进行传参给getenv即可通过系统调用接口getenv获取PATH环境变量的值。

#include <stdio.h>
#include <stdlib.h>int main()
{printf("PATH:%s\n",getenv("PATH"));return 0;
}

操作系统可以通过如下方式来区分当前用户是root用户还是普通用户,那么也就可以与文件的权限进行结合起来,如果登录用户是普通用户那么受权限限制,如果登录用户是root用户那么不受权限限制。

#include <stdio.h>
#include <string.h>
#include <stdlib.h>int main()
{char who[32];strcpy(who,getenv("USER"));if(strcmp(who,"root")==0){printf("你是root用户,不受权限限制\n");}else{printf("你是普通用户,受权限限制\n");}return 0;
}

命令行参数

命令行参数:是指在命令行界面运行程序时,跟随在程序名称后的额外输出参数,用于控制程序的运行或传递数据

int main(int argc,char* argv[])
{}

我们最常使用的main函数,同样是一个函数,main函数是被Startup()或CRTStartup()进行调用,所以main函数可以传参,可以带有额外参数,其中argc是参数的个数,argv是一个指针数组,我们使用命令行参数时,其实在bash中仅仅是输入了使用空格间隔的字符串,那么linux会将空格间隔出来的字符串的首字符的指针传递给这个argv指针数组,那么就可以使用argv+[]的形式获取这些字符串,那么根据字符串的不同去显示不同的内容或运作不同的操作,这就是linux中指令的选项的原型,例如mycmd -a使用空格分隔开的参数个数就对应是2

main函数可以传参,仅支持命令行参数是为了指令,命令,软件等提供命令行选项服务。

打印命令行参数表

1.对应的我们将argv这个指针数组叫做向量表,即命令行参数表,其中会默认在表的表的最后放入

一个NULL空,即

#include <stdio.h>
#include <string.h>
#include <stdlib.h>int main(int arvc,char* argv[])
{if(arvc!=2){printf("请输入%s -[a|b|c]\n",argv[0]);return 0;}else if(strcmp(argv[1],"-a") == 0){printf("%s[1]->%s ",argv[0],argv[1]);printf("功能1\n");}else if(strcmp(argv[1],"-b") == 0){printf("%s[1]->%s ",argv[0],argv[1]);printf("功能2\n");}else if(strcmp(argv[1],"-c") == 0){printf("%s[1]->%s ",argv[0],argv[1]);printf("功能3\n");}else{printf("default输入\n");}return 0;
}

运行结果:

命令行参数表,其底层如图所示

环境变量为什么具有全局属性

理论:

我们所运行的进程都是子进程,bash本身在启动的时候,会从操作系统的配置文件中读取环境变量信息,子进程会继承父进程交给子进程的环境变量,那么bash是所有进程的父进程,bash创建的子进程有可能在创建子进程,那么此时的进程关系就形成了一颗多叉树的形状,那么对应由于子进程要继承父进程的环境变量,而bash又是所有进程的父进程,那么bash中的环境变量在全部进程中都会有一份,那么此时环境变量就具有全局属性。

如何证明

我们先引出本地变量的概念,即在bash命令行中定义出的变量是本地变量,本地变量只在本bash内部有效,不会被子进程继承,本地变量不同于环境变量。

1.export设置一个新的环境变量,unset清除环境变量

2.本地变量可以通过export将自己变为环境变量

3.当本地变量使用export变成环境变量之后,可以通过unset将环境变量再变回本地变量

4.可以使用set查看环境变量和本地变量

我们在bash命令行中定义一个本地变量MY_VALUE,接着使用env显示环境变量,通过换到将数据传输给grep进行过滤MY_VALUE,结果什么都不显示,即无法在环境中找到MY_VALUE

接下来,我们通过echo $查看MY_VALUE,查看到MY_VALUE对应的值为555

本地变量xxx是不可以被子进程继承的,但export将xxx变为环境变量后,是可以被子进程继承的

内建命令和常规命令

我们思考一个问题,my_108是本地变量,是不会被子进程继承的,那为什么echo可以查看本地变量my_108的值呢?这是因为有两种类型命令,并不是所有命令都是通过fork创建子进程完成任务的。

1.常规命令--通过创建子进程完成

2.内建命令--bash不创建子进程,而是有自己亲自执行,类似于bash调用了自己写的,或者系统提供的函数

模拟内建命令

系统调用接口chdir,可以将当前调用的进程的工作目录更改至指定路径下

那么由于查看进程的工作目录(当前进程的路径即当前进程所在的目录位置)需要找到其PID和进入对应的proc中进程对应对应的PID中的cwd需要一定时间,所以需要在程序运行起来之后进行休眠,即使用系统调用接口sleep

通过第三方变量environ获取环境变量

我们还可以通过第三方变量environ获取环境变量,libc中定义的全局变量environ指向环境变量表,environ没有包含在任何头文件中,所以在使用时,要进行声明

extern char **environ

在使用environ时候,函数原型应该是int main(int argc,char*argv[])的形式

同时还应该声明二级指针environ

那么在使用的时候类似的就要类似于原main中第三个参数env去使用env[]去访问的形式,这里的environ也应该使用environ[]的形式去访问环境变量。

http://www.xdnf.cn/news/1311679.html

相关文章:

  • 同创物流学习记录2·电车
  • 链式二叉树的基本操作——遍历
  • 实时计算 记录
  • 美国服务器环境下Windows容器工作负载基于指标的自动扩缩
  • 从盲区到全域:黎阳之光视频孪生+AI智能算法驱动智慧机场三维感知革命
  • 4.6 Vue 3 中的模板引用 (Template Refs)
  • CSS复习
  • Jenkins安装部署(Win11)和常见配置镜像加速
  • SysTick寄存器(嘀嗒定时器实现延时)
  • 要导入StandardScaler类进行数据标准化,请使用以下语句:
  • VS Code配置MinGW64编译ALGLIB库
  • 《C语言程序设计》笔记p10
  • 【数据分享】上市公司供应链成本分摊数据(2007-2024)
  • 【数据结构】-2- 泛型
  • leetcodehot100 矩阵置零
  • 基于Spring Boot 4s店车辆管理系统 租车管理系统 停车位管理系统 智慧车辆管理系统
  • 谷歌手机刷机和面具ROOT保姆级别教程
  • 利用 Java 爬虫按图搜索淘宝商品(拍立淘)实战指南
  • 《解耦的艺术:Python 观察者模式在 GUI 与事件驱动中的实战》
  • cPanel Python 应用部署流程
  • 【自动化运维神器Ansible】Ansible逻辑运算符详解:构建复杂条件判断的核心工具
  • Scala面试题及详细答案100道(11-20)-- 函数式编程基础
  • PCIE EP 框架
  • C#单元测试(xUnit + Moq + coverlet.collector)
  • RK3568 NPU RKNN(四):RKNN-ToolKit2性能和内存评估
  • springboot集成websocket
  • SpringBoot 集成Ollama 本地大模型
  • RH134 访问网络附加存储知识点
  • 【图论】分层图 / 拆点
  • 计算机存储器分类和层次结构详解