Linux进程学习【环境变量】

简介: 环境变量 是一个即陌生又熟悉的词,说陌生是因为大多数普通用户都接触不到 环境变量 配置,说熟悉是因为很多程序又都离不开 环境变量,比如编写 Java 时需要提前安装 jdk,配置好 Java 的环境,才能正常编写代码,python 也是需要配置编码环境;而在我们的 Linux 中也有环境变量,由 环境变量 构成的集合称做 环境变量表;我们还可以调整 进程 的优先级,使得 进程 运行更加灵活

✨个人主页: Yohifo

🎉所属专栏: Linux学习之旅

🎊每篇一句: 图片来源

🎃操作环境: CentOS 7.6 阿里云远程服务器


Perseverance is not a long race; it is many short races one after another.


毅力不是一场漫长的比赛;是许多短跑一个接一个。

3cd397e384fa93fcaf977706ff20502.png


📘前言


环境变量 是一个即陌生又熟悉的词,说陌生是因为大多数普通用户都接触不到 环境变量 配置,说熟悉是因为很多程序又都离不开 环境变量,比如编写 Java 时需要提前安装 jdk,配置好 Java 的环境,才能正常编写代码,python 也是需要配置编码环境;而在我们的 Linux 中也有环境变量,由 环境变量 构成的集合称做 环境变量表;我们还可以调整 进程 的优先级,使得 进程 运行更加灵活


8b047a3e91e36b7a800bba89fb8e103.png


📘正文


📖环境变量


首先需要先来看看什么是 环境变量


一般是指在操作系统中用来指定操作系统运行环境的一些参数

例如在编译程序时,我们是不关心动态库位于什么地方,编译器链接时也只需要通过对应的 环境变量 就能找到动态库进行链接

环境变量 有着自己的特殊用途,还有有些具有全局属性,可以供所有 进程 共享

环境变量 有很多个,把它们聚在一起管理,就构成了 环境变量列表


环境变量列表 中的常见 环境变量:


PATH 系统命令搜索路径

USER 当前用户名

PWD 当前所处路径

我们可用通过指令 echo $NAME 查看当前环境变量信息(NAME 指环境变量名)


//比如查看用户信息
$ echo$USER

f5e9924dfbb590eb71f4b4243bb41b0.png


🖋️环境变量列表


下面来看看 环境变量列表 长什么样

通过指令查看


$ env

c6fac5dce65211daf78d0bdd88ca488.png

环境变量表是以指针数组的形式存储的

28be602c0812cce0a74506401127aa3.png

也可以通过 set 指令查看 环境变量表,不过 set 指令显示的内容比 env 多得多,因为 set 还会显示 本地环境变量 信息


$ set //显示更加丰富的环境变量表


这里简单说一下 PATH 的作用


Linux 中的各种指令都是用 C语言 编写的程序,所以:运行指令 == 运行程序

PATH 环境变量中有存储各种指令(程序)的路径,当我们直接输入指令时,OS会根据 PATH 提供的路径搜索程序,找到了就会直接运行对应指令(程序)

而我们自己编写的程序则是需要通过 ./可执行程序 的方式运行,因为此时路径不被包含在 PATH 变量中

总之:PATH 存储路径中若包含程序,可以直接通过程序名运行程序

这就是各种指令,如 ls、pwd、touch 的运行原理


c96906c1764ef37e6a1b3d49fce4f3d.png

我们可以通过这一特性,将自己的可执行程序路径添加到 PATH 变量中

0b152f82492b9c7ed760e5e3ac32d88.png

//注意:路径为绝对路径
//不能写成 exportPATH=路径 这样会把所有指令都覆盖
$ exportPATH=$PATH:/home/Yohifo/linux/Explore/code/Test_2_21


7459f0924ea290451a67fe5af11709c.png

现在可以像指令一样直接运行程序


注意: 普通用户添加的环境变量只有本次登录有效,下次再登录时,环境变量列表会被重置


普通用户修改 环境变量列表 没什么大问题,但 root 需要谨慎了,避免造成严重后果


除此之外,我们还可以把程序写在 /usr/bin 目录下,此时也是可以直接通过程序名运行程序的

4df08b3fcc6dade766a4f56740bb28f.png

如上就是安装、卸载应用原理


🖋️添加环境变量


shell 可以读取到命令和命令行,我们可以直接通过命令的方式添加 环境变量


先来看看比较简单的 本地变量 添加

环境变量表 具有全局属性,可以供所有子进程共享,倘若我们不想让 环境变量 被共享,可以设置 本地变量


$ TEST=private  //可以直接在命令行中添加本地变量

88307dd7a7207a9eb3b1f988d00552f.png


现在的 TEST 环境变量是不被子进程共享的


如果想删除已经设置的 本地环境变量,可以通过 unset NAME 移除设置


$ unset TEST  //移除已设置的本地环境变量


想让 TEST 进入 环境变量表 也很简单,只需要加上关键字 export


$ exportTEST=public  //此时环境变量已进入环境变量表

874a3e0dad2ad5bbaf7843d1631d32f.png


a62be0194c6728b8a6de4dc9b640a50.png

🖋️获取环境变量


环境变量 针对的是特定的人在特定场合干特定的事,这句话读起来有点绕,实际上:


  • 有许多 环境变量 存储的是用户的个人信息,不同用户的 环境变量表 各不相同
  • 我们可以利用 环境变量 做信息验证,根据不同变量(选项)执行不同操作
  • 比如 ls 指令是显示当前目录下的文件信息,而 ls -a 则是显示详细信息,原理很简单,调用 ls 程序时传递了 -a 这个选项,使得程序一对比,就知道要执行显示详细信息这个操作


环境变量表具有全局属性,程序运行时,环境变量表会传递给程序使用


因此我们可以在程序中获取 环境变量


通过全局变量 environ (char** 类型)获取

通过函数 getenv(NAME) 获取,这个比较常用

通过 main 函数中的第三个参数 char* envp[] 获取

前两种方式比较简单,可以通过一个小程序观察到,而最后一种方式 需要结合主函数参数 的知识观察,将放在下一个部分详细讲解


先来看看前两种方式获取 环境变量


#include<iostream>#include<stdlib.h>  //getenv 需要使用这个头文件usingnamespacestd;
externchar**environ; //声明使用intmain()
{
//cout << "Hello environment variable!" << endl;  //你好环境变量!intpos=0;
while(pos<5)
  {
cout<<environ[pos] <<endl; //获取部分环境变量信息pos++;
  }
cout<<endl<<"========================"<<endl<<endl;
//通过函数获取cout<<"PWD="<<getenv("PWD") <<endl;
return0;
}

ee768aaaafeb62be02a0bac621ecac4.png

可以自己尝试通过 getenv 函数验证本地变量不进入环境变量表这个现象


指令 pwd 实现非常简单,通过 getenv("PWD") 获取信息,再输出即可,我们可以自己实现 mypwd


#include<iostream>#include<stdlib.h>usingnamespacestd;
intmain()
{
//调用程序,获取环境变量信息cout<<getenv("PWD") <<endl;
return0;
}

42ba3a7fe00c42a4154cb812ac58ac4.png


一些不带选项,且比较简单的指令,我们是 可以直接利用函数获取 环境变量 模拟实现


📖主函数参数


main 函数有两种写法:带参与不带参,平常我们都是使用不带参数的 main 函数作为程序入口,对于函数参数很少关注,今天就来看看 main 函数中的参数吧


🖋️三个参数


main 函数中有三个参数,分别是:


  • int argc 传入程序中的元素数,./程序名 算一个
  • char* argv[] 传入程序中的元素表,由 bash 制作,传给 main 函数
  • char* envp[] 环境变量表,所谓全局性就是指 main 函数可以通过此参数获取到环境变量表的信息


5f7cbe3574e0d075ce18859a659bb5f.png

如何证明它们存在呢?

程序就是最好的证明

2a5c7a2bde5bec0eab808fc5464455e.png

#include<iostream>usingnamespacestd;
intmain(intargc, char*argv[], char*envp[])
{
cout<<"现在传入的有效元素数为:"<<argc<<endl;
cout<<"=========================="<<endl;
cout<<"通过元素表打元素信息"<<endl;
intpos=0;
while(pos<argc)
  {
cout<<argv[pos] <<endl;
pos++;
  }
cout<<"=========================="<<endl;
cout<<"使用环境变量表获取前五个环境变量信息"<<endl;
pos=0;
while(pos<5)
  {
cout<<envp[pos] <<endl;
pos++;
  }
return0;
}


main 函数中的三个参数各有各的作用


enpv 也可以获取环境变量,效果等价于 environ


环境变量表 能被共享的本质: 环境变量表会通过传参数的形式传给程序使用


🖋️选项调用


argv 可以实现指定指令完成指定功能的任务


首先我们需要在程序中提前设置好不同选项的运行结果


#include<iostream>#include<string.h>#include<stdlib.h>usingnamespacestd;
//打印提示信息voidUsage(constchar*str)
{
cout<<str<<" -[a | b | c]"<<endl;
}
intmain(intargc, char*argv[], char*envp[])
{
//首先进行身份检验if(strcmp(getenv("USER"), "Yohifo") !=0)
  {
cout<<"当前用户为:"<<getenv("USER") <<endl;
cout<<"非法使用他人程序,操作被拒绝!"<<endl;
return0;
  }
//确保选项只有一个if(argc!=2)
  {
cout<<"指令错误,尝试重新输入"<<endl;
Usage(argv[0]);
return0;
  }
//验证成功后,进行选项分流if(strcmp(argv[1], "-a") ==0)
  {
cout<<"执行 a 任务"<<endl;
cout<<"…………………………"<<endl;
cout<<"任务执行完成"<<endl; 
  }
elseif(strcmp(argv[1], "-b") ==0)
  {
cout<<"执行 b 任务"<<endl;
cout<<"…………………………"<<endl;
cout<<"任务执行完成"<<endl; 
  }
elseif(strcmp(argv[1], "-c") ==0)
  {
cout<<"执行 c 任务"<<endl;
cout<<"…………………………"<<endl;
cout<<"任务执行完成"<<endl;     
  }
else  {
cout<<"指令错误,尝试重新输入"<<endl;
Usage(argv[1]);
return0;
  }
return0;
}


通过不同的选项,调用不同的功能,这就是 main 函数参数存在的意义


选项会同程序名一起,构成一张表,传给 char* argv[] 参数


aa79c9757dc163da4a15d5427b2a432.png

这种玩法叫做 命令行参数,后续学习中将会经常用到


📖进程优先级


进程 还有优先级之分,优先级高的 进程 会被优先调用


CPU 资源是有限的,需要合理分配

3c42befbf9b18112acdd353c124b6f4.png

Linux 给我们提供了修改 进程 优先级的权限,目的就是让我们对多任务运行进行合理处理,提高系统运行效率



🖋️优先级查看


在 进程 的PCB信息中,还包含了这些信息:


  • UID 身份标识
  • PRI 进程优先级,默认为 80
  • NI 进程修正值,这个只有 Linux 中有,配合修改优先级,范围为 [-20, 19]
  • 我们可以通过 ps 指令查看进程优先级情况


//注:其中的 myfile 是可执行程序名
$ ps-al | head -1 && ps-al | grep myfile  //查看进程优先级信息


2b7f1842c7796286e836abcedfa9c6f.png

🖋️优先级修改


进程优先级 可以被修改,但很少有人会主动修改


修改步骤


  • 输入 top 指令进入任务管理器
  • 输入 r 进入修改模式
  • 再根据想要修改的进程,输入 PID
  • 最后输入 NI 值,完成修改


dd05b1b02fb74ca2903ede9a8b7fd673 (1).gif

注意:


  • NI值区间为 [-20, 19],设置时超出部分无效
  • 修改优先级时,最终优先级 = 初始优先级 + NI值,优先级的修改行为并不是连续的,每次都是在最开始的基础上进行修改(默认为 80)
  • 调度器不允许存在 优先级失衡 的情况,因此优先级修改不能太激进


📖进程特点


下面来简单小结一下进程的特点


  • 竞争性:CPU 资源有限,进程 间存在竞争
  • 独立性:进程 是相互独立运行的,互不干扰 (重要)
  • 并行:多个 进程 可以在多个 CPU 上同时运行
  • 并发:在一个 CPU 下采用 进程 切换的方式运行多个 进程


📘总结


以上就是有关进程学习【环境变量】的全部内容了,本文主要研究对象是 环境变量,知道了 环境变量表 的存在,以及主函数是如何得到 环境变量表 表并实际运用的;最后还谈到了 进程优先级 问题,学习了优先级修改的相关指令;进程 最大的特性之一就是 独立性,父子进程 间会发生 写时拷贝 机制,这种神奇的现象是如何产生的呢?敬请期待下篇中关于 进程地址空间 的相关文章


如果你觉得本文写的还不错的话,期待留下一个小小的赞👍,你的支持是我分享的最大动力!


如果本文有不足或错误的地方,随时欢迎指出,我会在第一时间改正

目录
相关文章
|
16天前
|
存储 安全 Linux
|
17天前
|
缓存 监控 Linux
linux进程管理万字详解!!!
本文档介绍了Linux系统中进程管理、系统负载监控、内存监控和磁盘监控的基本概念和常用命令。主要内容包括: 1. **进程管理**: - **进程介绍**:程序与进程的关系、进程的生命周期、查看进程号和父进程号的方法。 - **进程监控命令**:`ps`、`pstree`、`pidof`、`top`、`htop`、`lsof`等命令的使用方法和案例。 - **进程管理命令**:控制信号、`kill`、`pkill`、`killall`、前台和后台运行、`screen`、`nohup`等命令的使用方法和案例。
51 4
linux进程管理万字详解!!!
|
19天前
|
Linux Shell 数据安全/隐私保护
|
8天前
|
存储 运维 监控
深入Linux基础:文件系统与进程管理详解
深入Linux基础:文件系统与进程管理详解
48 8
|
7天前
|
存储 运维 Linux
如何在 Linux 系统中使用 envsubst 命令替换环境变量?
`envsubst` 是 Linux 系统中用于替换文本中环境变量值的实用工具。本文分三部分介绍其工作原理、使用方法及实际应用,包括配置文件替换、脚本执行中环境变量替换和动态生成文件等场景,帮助用户高效利用 `envsubst` 进行开发和运维工作。
17 4
|
17天前
|
算法 Linux 定位技术
Linux内核中的进程调度算法解析####
【10月更文挑战第29天】 本文深入剖析了Linux操作系统的心脏——内核中至关重要的组成部分之一,即进程调度机制。不同于传统的摘要概述,我们将通过一段引人入胜的故事线来揭开进程调度算法的神秘面纱,展现其背后的精妙设计与复杂逻辑,让读者仿佛跟随一位虚拟的“进程侦探”,一步步探索Linux如何高效、公平地管理众多进程,确保系统资源的最优分配与利用。 ####
52 4
|
18天前
|
缓存 负载均衡 算法
Linux内核中的进程调度算法解析####
本文深入探讨了Linux操作系统核心组件之一——进程调度器,着重分析了其采用的CFS(完全公平调度器)算法。不同于传统摘要对研究背景、方法、结果和结论的概述,本文摘要将直接揭示CFS算法的核心优势及其在现代多核处理器环境下如何实现高效、公平的资源分配,同时简要提及该算法如何优化系统响应时间和吞吐量,为读者快速构建对Linux进程调度机制的认知框架。 ####
|
19天前
|
消息中间件 存储 Linux
|
25天前
|
运维 Linux
Linux查找占用的端口,并杀死进程的简单方法
通过上述步骤和命令,您能够迅速识别并根据实际情况管理Linux系统中占用特定端口的进程。为了获得更全面的服务器管理技巧和解决方案,提供了丰富的资源和专业服务,是您提升运维技能的理想选择。
31 1
|
1月前
|
Linux 开发工具
【Linux快速入门(二)】Linux与ROS学习之编译基础(make编译)
【Linux快速入门(二)】Linux与ROS学习之编译基础(make编译)
下一篇
无影云桌面