Linux进程理解【环境变量】
提到环境变量
,大家可能有些陌生,如果编写过Java
就知道,编写Java
需要提前安装JDK
,这个操作就是配置Java
的编码环境,在Linux
中当然也少不了环境变量
,下面我们就一起来看看
1. 环境变量
环境变量的概念
- 环境变量一般是指在操作系统中用来指定操作系统运行环境的一些参数
举个例子:我们在编写C/C++代码的时候,在链接的时候,从来不知道我们的所链接的动态静态库在哪里,但是照样可以链接成功,生成可执行程序,原因就是有相关环境变量帮助编译器进行查找。环境变量通常具有某些特殊用途,并且环境变量在系统当中通常具有全局特性
常见环境变量
PATH
:系统命令的搜索路径HOME
:指定用户的主工作目录(即用户登陆到Linux
系统中时,默认的目录)SHELL
: 当前Shell
,它的值通常是/bin/bash
通过指令echo $环境变量名
,来查看指定环境变量信息
echo $环境变量名 //查看指定环境变量
1.1 环境变量表
将很多环境变量聚集到一起管理,就组成了环境变量表
通过指令env
,来查看本用户对应的环境变量表
env //查看本用户环境变量表
XDG_SESSION_ID=255667
HOSTNAME=VM-4-2-centos //机器名
SHELL=/bin/bash //shell
TERM=xterm
HISTSIZE=3000 //历史命令数量最大值
SSH_CLIENT=111.173.233.59 14786 22
OLDPWD=/home/sakura/Test
SSH_TTY=/dev/pts/0
USER=sakura //用户
LS_COLORS=rs=0:di=01;34:ln=01;36:mh=00:pi=40;33:so=01;35:do=01;35:bd=40;33;01:cd=40;33;01:or=40;31;01:mi=01;05;37;41:su=37;41:sg=30;43:ca=30;41:tw=30;42:ow=34;42:st=37;44:ex=01;32:*.tar=01;31:*.tgz=01;31:*.arc=01;31:*.arj=01;31:*.taz=01;31:*.lha=01;31:*.lz4=01;31:*.lzh=01;31:*.lzma=01;31:*.tlz=01;31:*.txz=01;31:*.tzo=01;31:*.t7z=01;31:*.zip=01;31:*.z=01;31:*.Z=01;31:*.dz=01;31:*.gz=01;31:*.lrz=01;31:*.lz=01;31:*.lzo=01;31:*.xz=01;31:*.bz2=01;31:*.bz=01;31:*.tbz=01;31:*.tbz2=01;31:*.tz=01;31:*.deb=01;31:*.rpm=01;31:*.jar=01;31:*.war=01;31:*.ear=01;31:*.sar=01;31:*.rar=01;31:*.alz=01;31:*.ace=01;31:*.zoo=01;31:*.cpio=01;31:*.7z=01;31:*.rz=01;31:*.cab=01;31:*.jpg=01;35:*.jpeg=01;35:*.gif=01;35:*.bmp=01;35:*.pbm=01;35:*.pgm=01;35:*.ppm=01;35:*.tga=01;35:*.xbm=01;35:*.xpm=01;35:*.tif=01;35:*.tiff=01;35:*.png=01;35:*.svg=01;35:*.svgz=01;35:*.mng=01;35:*.pcx=01;35:*.mov=01;35:*.mpg=01;35:*.mpeg=01;35:*.m2v=01;35:*.mkv=01;35:*.webm=01;35:*.ogm=01;35:*.mp4=01;35:*.m4v=01;35:*.mp4v=01;35:*.vob=01;35:*.qt=01;35:*.nuv=01;35:*.wmv=01;35:*.asf=01;35:*.rm=01;35:*.rmvb=01;35:*.flc=01;35:*.avi=01;35:*.fli=01;35:*.flv=01;35:*.gl=01;35:*.dl=01;35:*.xcf=01;35:*.xwd=01;35:*.yuv=01;35:*.cgm=01;35:*.emf=01;35:*.axv=01;35:*.anx=01;35:*.ogv=01;35:*.ogx=01;35:*.aac=01;36:*.au=01;36:*.flac=01;36:*.mid=01;36:*.midi=01;36:*.mka=01;36:*.mp3=01;36:*.mpc=01;36:*.ogg=01;36:*.ra=01;36:*.wav=01;36:*.axa=01;36:*.oga=01;36:*.spx=01;36:*.xspf=01;36: //配色方案
LD_LIBRARY_PATH=:/root/.VimForCpp/vim/bundle/YCM.so/el7.x86_64:/home/sakura/.VimForCpp/vim/bundle/YCM.so/el7.x86_64
PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/root/bin
MAIL=/var/spool/mail/root
PWD=/home/sakura //当前文件路径
LANG=en_US.utf8
HOME=/home/sakura //家目录
SHLVL=2
LOGNAME=sakura //当前登录用户
SSH_CONNECTION=111.173.233.59 14786 10.0.4.2 22
LESSOPEN=||/usr/bin/lesspipe.sh %s
PROMPT_COMMAND=history -a; history -a; history -a; history -a; printf "\033]0;%s@%s:%s\007" "${USER}" "${HOSTNAME%%.*}" "${PWD/#$HOME/~}"
XDG_RUNTIME_DIR=/run/user/0
HISTTIMEFORMAT=%F %T
_=/usr/bin/env
还可以通过set
指令,查看本地变量和本用户环境变量表,内容很多,并不是很常用
set //查看本地变量和本用户环境变量表
环境变量表实际上就是一个指针数组,指针指向具体的环境变量内容
这里有一个问题:在Linux
下,ls
、pwd
等指令本质也是可执行程序,和我们自己编写的可执行程序没有什么区别,而我们自己实现的需要带上./
才能执行,这是为什么呢?
PATH
环境变量中,存储着各种指令的路径,Linux
中的指令都是C语言编写的,本质都是可执行程序,我们执行指令就相当于运行程序,OS
会根据PATH
提供的路径,找到对应指令(可执行程序)来直接运行- 我们自己编写的程序不被包含到PATH环境变量中,直接执行会找不到,所以需要加上
./
才能运行
知道了这一点,那么我们如果将自己实现的可执行程序加入到PATH变量中,是否也可以想指令一样使用呢?答案是肯定的!
export PATH=$PATH:绝对路径 //添加路径到PATH变量
直接像指令一样使用是无法运行的,下面我们将路径加入PATH
变量中
这样就可以像指令一样运行我们自己编写的程序了
注意:
- 普通用户修改环境变量列表没什么大问题,本次修改只在本次有效,再次登录时环境列表会被重置
root
用户尽量不要修改环境变量列表,避免出现意外
我们还可以将程序写到usr/bin目录下,也可以起到以上的效果
我们可以在这个目录下看到熟悉的ls
等指令,将程序写到此处,就相当于将应用安装到了系统中,指令在这删除之后也无法再使用了,这也就是Linux
下安装和卸载软件的原理
1.2 添加环境变量
通过变量名=内容
直接在命令行中添加本地变量,可以设置本地变量,本地变量只能供shell
使用,是不被子进程共享的
变量名=内容 //添加本地变量
通过指令unset 本地变量名
,可以删除本地变量
unset 本地变量名 //取消本地变量
加上关键字export
就可以将变量写入环境变量表,环境变量表具有全局属性,被所有子进程共享
1.3 获取环境变量
程序运行时,环境变量表会传递给程序使用,可以在程序中获取环境变量
- 使用`extern char environ
二级字符指针获取,它是指向
envp`字符串指针数组的** - 使用函数
char* getenv(char* name)
获取 - 使用main函数的第三个参数
char* envp
获取
先来看看使用extern char** environ
二级字符指针获取
#include <stdio.h>
#include <unistd.h>
extern char** environ; //声明
int main()
{
for(int i = 0; environ[i]; ++i){
printf("environ[%d]->%s\n",i ,environ[i]);
}
return 0;
}
当然也可以通过函数char* getenv(char* name)
获取,获取成功返回环境变量内容,失败则返回NULL
#include <stdio.h>
#include <stdlib.h>
int main()
{
char* user = getenv("USER");
if(user == NULL)
{
perror("无此环境变量!\n");
exit(-1);
}
else
{
printf("USER=%s\n", user);
}
return 0;
}
结合以上内容,我们通过getenv()
函数获取环境变量信息,再将程序路径添加到PATH变量中,就可以自己模拟实现指令了
#include <stdio.h>
#include <stdlib.h>
int main()
{
printf("%s", getenv("PWD"));
return 0;
}
使用第三种方法获取之前,我们先来讲解一下主函数main
的三个参数
2. main函数参数
2.1 参数功能
我们平时使用main函数都是不带参的,其实它是有三个参数的
- int argc,表示传入程序中的元素个数
- char* argv[],表示传入程序中的元素表,由bash制作
- char* envp[],表示环境变量表
argv
也是一个字符串指针数组,每个元素对应的一个字符串,字符串以’\0’
为结束标志,数组以NULL为
标识结束数组的
我们还是通过程序来观察三个参数
#include <stdio.h>
#include <stdlib.h>
int main(int argc, char* argv[], char* envp[]) {
printf("传入的有效元素个数:%d\n", argc);
printf("元素表元素信息:\n");
for(int i = 0; i < argc; i++)
{
printf("argv[%d]->%s\n", i, argv[i]);
}
printf("获取环境变量表前七个环境变量的信息:\n");
for(int i = 0; i < 7; i++)
{
printf("envp[%d]->%s\n", i, envp[i]);
}
return 0;
}
通过程序运行可以发现
./mytest
这个可执行程序也会被传入元素表中- 我们也可以自己传入元素到元素表中,这也就是指令后可以跟上参数列表的原理了,类似
ls -a -l
,ls
就是一个可执行程序,-a
、-l
就是传入参数列表 main
函数可以通过envp
参数获取到环境变量表的信息,也就是环境变量表可以通过参数传递给程序使用,这就是环境变量表有全局属性,能被共享的本质了
2.2 参数列表
下面我们来看看参数列表的使用,也就是利用 char* argv[]
来实现指定参数完成指定任务
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
//打印提示信息
void Argvment(const char* name)
{
printf("Argvment: %s [-a|-b|-c]\n", name);
exit(0);
}
int main(int argc, char* argv[])
{
if(argc != 2) //确保选项只有一个
{
printf("指令错误,请重新输入!\n");
Argvment(argv[0]);
return 0;
}
if(strcmp(argv[1], "-a") == 0)
{
printf("执行任务a!\n");
}
else if(strcmp(argv[1], "-b") == 0)
{
printf("执行任务b!\n");
}
else if(strcmp(argv[1], "-c") == 0)
{
printf("执行任务c!\n");
}
else
{
printf("指令错误,请重新输入!\n");
}
return 0;
}
选项和程序一起构成一张元素表,传递给 char* argv[]
参数,通过不同的选项,来调用不同的功能
3. 进程优先级
进程优先级
就是指的是进程的优先权,也就是指CPU资源分配的先后顺序!优先权高的进程先执行,优先级低的后执行!这样的目的是为了改善系统性能!
3.1 系统进程查看
进程的PCB
信息都有自己的意义
UID
:执行者身份PID
:进程代号PPID
:父进程代号PRI
:进程优先级,默认为80
NI
:进程优先级对应的修正值,范围是[-20, 19]
其中
PRI
的一个求法:PIR(new) = PRI(old) + nice
。另外我们的进程会通过CPU
来做计算,CPU
中有调度器,这个调度器的作用就是来对进程的优先级一碗水端平,不会过度的使得其进程优先级很高,也不会过度的使得其进程优先级很低,所以这里的NI
值也不会很高,这样就可以达到一碗水端平的目的。
通过ps
指令来查看进程信息
ps -l/ps -al //查看进程信息
3.2 优先级修改
优先级修改步骤
- 使用
top
命令进入任务管理器 - 输入
r
进入修改模式 - 输入想要修改的进程的
PID
- 输入
NI
值完成修改
修改进程优先级的操作不难,而且很少会修改,这里我就不演示了
注意:
修改优先级后,最终优先级
=
初始优先级+
NI值NI
值的范围为[-20, 19]
,设置时超出部分将会无效- 优先级的修改行为并不是连续的,每次修改都是在最开始的基础上进行,进程重新开始后其
PRI
和NI
都会恢复原值
4. 进程特性
总结一下进程的特性
- 竞争性:系统进程数目很多,但是CPU资源有限,所以进程之前存在竞争
- 独立性:多进程运行需要独享资源,互不干扰
- 并行:多个进程可以在多个CPU下分别同时运行
- 并发:多个进程在一个CPU下采用进程切换的方式,在一段时间内,让多个进程都得以推进
Linux进程理解—环境变量,到这里就介绍结束了,本篇文章对你由帮助的话,期待大佬们的三连,你们的支持是我最大的动力!
文章有写的不足或是错误的地方,欢迎评论或私信指出,我会在第一时间改正