【Linux】进程(6):环境变量

大家好,我是苏貝,本篇博客带大家了解Linux进程(6):环境变量,如果你觉得我写的还不错的话,可以给我一个赞👍吗,感谢❤️


目录

(A)PATH

我们知道,在命令行中输入的系统指令和我们自己写的程序最后都会成为进程,但为什么系统指令前面不需要绝对/相对路径,而我们自己写的程序需要呢?

因为在Linux中,存在一些全局的设置,它们告诉命令行解释器,应该去哪些路径下寻找可执行程序

下面以环境变量PATH为例

先打印环境变量PATH的内容

注意:PATH前要加$

PATH的内容中有很多路径,它们以: (冒号)作为分隔符

PATH中的路径有什么用呢?

  1. bash在执行命令的时候,需要先找到命令才能在未来将命令加载,那在哪找命令呢?如果命令前面没加绝对/相对路径,那么bash就会在PATH里的路径中查找,如果找到了,就加载;没找到,就会报错。
  2. 执行which命令时,which也是在PATH的路径里查找

现在,我想让我们自己写的程序和系统指令一样,前面不需要绝对/相对路径即可执行,有什么办法呢?有2种方法

方法1:将程序拷贝到PATH内容的路径下(不建议)

注意:此时需要用root管理员身份进行拷贝(直接转换成root身份或者sudo提权)(相当于将myprocess程序安装到Linux系统中)

我们非常不建议这种写法,所以现在我们将myprocess程序从/usr/bin路径下删除(相当于卸载程序)

当我们直接在命令行输入myprocess,bash报错,表明myprocess确实从/usr/bin路径下删除了

方法2:将程序的当前路径添加到PATH中

程序的当前路径为Linux_code/lesson_14,先直接将PATH赋值为Linux_code/lesson_14,所以PATH原先的内容完全被覆盖,只有Linux_code/lesson_14。此时再使用ls等系统命令就会报错,因为它们都在/usr/bin目录下,而/usr/bin不在环境变量PATH中

现在关掉该终端,重新打开一个终端,再来查看PATH的内容

我们发现,PATH的内容又变回原来的了,这是为什么?

系统中很多的配置,在我们登录Linux系统的时候,已经被加载到了bash进程中(内存里)。最开始的环境变量不是在内存中,而是在系统的对应的配置文件中。当我们登录Linux系统时,环境变量对应的配置文件被加载到了bash进程中,所以默认我们查到的环境变量是内存级的,我们对环境变量PATH的修改也是在内存里修改,并不影响环境变量对应的配置文件。因此当我们关闭终端后,bash进程被杀掉,bash占据的内存空间被释放,再次打开终端,bash进程重新加载环境变量对应的配置文件,所以PATH的内容变回原来的了

虽然如此,但我还是不想在我们自己写的程序前面加绝对/相对路径,不能用我们上面的直接赋值的方法,怎么办?

PATH=$PATH: /home/zy/Linux_code/lesson_14,中间用: (冒号)分隔

下一个问题:我们能否将PATH的内容永久修改呢?可以,根据我们上面的解释,只需要修改对应的配置文件。那环境变量对应的配置文件在哪里?

(B)环境变量对应的配置文件

先将当前目录变成家目录(cd ~),再执行ls -al,列出家目录的所有文件的详细信息,包括以.开头的隐藏文件

找到.bash_profile和.bashrc文件,这就是环境变量对应的配置文件。打开2个文件

现在将myprocess当前路径加入到配置文件中PATH里即可


将配置文件修改回去

(C)更多的环境变量

1.环境变量HOME:家目录所在的环境变量

普通用户的家目录(以普通用户zy为例)是/home/zy,所以它的环境变量HOME=/home/zy

root的家目录是/root,所以它的环境变量HOME=/root

2.环境变量PWD

系统怎么知道我们当前在哪个目录下呢?

系统有个会变化的环境变量PWD,它会随着我们路径的变化,将当前路径动态地记录在PWD中

3.环境变量SHELL

shell是命令行解释器,常见的Shell工具包括:sh、bash、csh、tcsh、ash 等,所以我们怎么知道当前我们启动的是哪个呢?

所以我们的shell是bash

4.环境变量HISTSIZE:记录的历史命令的个数

在命令行中,我们可以通过按上下键翻到我们的历史命令,能上翻就表明我们曾经的命令是被Linux系统记录下来的,但系统不能一直记录吧,所以用HISTSIZE表示Linux系统能记录最新的多少个历史命令

我们可以用history命令来查看这1000条历史命令

5.env:查看所有的环境变量

HOSTNAME是主机名

(D)环境变量操作

env和echo之前有介绍过,这里不再赘述

export name=value:导出环境变量,环境变量名为name,值为value

现导出一个叫THIS_IS_MY_ENV的环境变量,值为hello

关掉终端后,环境变量THIS_IS_MY_ENV还存在吗?

不存在,因为这是在内存中导出了新的环境变量,并没有添加到对应的配置文件中

unset name:取消环境变量

本地变量

env查不到,所以asdf不是环境变量,但又能通过echo $查看内容,叫这样的为本地变量

(E)理解环境变量 系统

1. 用代码拿到环境变量

修改.c文件

先不要管environ是什么意思,我们目前只知道它的类型是char**。指向程序

我们发现,这就是我们的环境变量。在命令行参数中,我们讲过,父进程的数据,默认能被子进程看到并访问。对于./myprocess进程,其父进程是bash,且在Linux登录时,环境变量对应的配置文件被加载到了bash进程中,所以./myprocess进程能看到并访问bash的数据(环境变量)是可以理解的。

环境变量可是很多的,bash内部是如何组织的呢?

bash进程启动的时候,会从操作系统的配置文件中形成char* env[ ],它是一个指针数组,元素类型为char*,即元素指向某个字符或字符串。事实上,env数组的元素就指向环境变量,数组的最后一个元素指向NULL

你有没有发现,env数组和我们在命令行参数中讲的argv数组很像,都是指针数组,元素类型都是char*,最后一个元素都指向NULL...,所以main函数其实也可以有3个参数,分别是int argc,char* argv[ ]和char* env[ ]

因此main函数可以没有参数,也可以有2或3个参数

事实上,bash进程在启动的时候,默认会给子进程2张表:argv[ ]命令行参数表(用户从命令行中输入),env[ ]环境变量表(从OS的配置文件中来)。bash会通过各种方式将它们交给子进程

environ就是指向env数组

其实我们还可以用env数组来打印出环境变量

修改.c文件


上面的两种方法(char** environ和char* env[ ] )都是将环境变量全部打印出来,那如果我只想打印某个环境变量(如PATH),怎么办?

用getenv函数

先用man getenv命令查看getenv函数:头文件是<stdlib.h>,参数是环境变量名(如PATH),返回值类型是char*

修改.c文件

所以想要用代码打印环境变量,有3种方法

extern char** environ

通过main函数的参数:char* env[ ]

getenv函数

2. 环境变量再理解

环境变量具有系统级的全局属性

命令行中启动的程序,都会变成进程,且都是bash的子进程。那如果bash的子进程1再次fork形成子进程2,那子进程2能否看到bash的环境变量呢?

可以,因为环境变量具有系统级的全局属性,环境变量本身会被子进程继承下去。也就是说,如果将bash进程作为树的根节点,bash的子进程作为根节点的孩子节点,bash的子进程的子进程作为bash的子进程的孩子节点......,那么这整棵树都可以看见并访问bash进程的环境变量

内建命令:由bash亲自执行的命令

在Linux系统中,有80%的命令都是bash创建子进程执行的,如:ls,mkdir,cp等;也有一些是由bash亲自执行的命令,叫内建命令,如:export,echo

现在证明export是内建命令

先导出新的环境变量myval并赋值,在bash里面能找到myval

假如export是由bash创建子进程执行的,那么myval就不应该被bash看到,因为父进程不会看到被子进程修改的数据。所以export是内建命令

还能通过下面的方法证明:

先将环境变量PATH的内容置为空,而bash在执行普通命令时,需要先在PATH内容的路径下查找,只有找到了才能执行命令。现在PATH的内容为空,所以bash在PATH里没有找到ls,touch,cd等命令,所以这些命令都不能被执行。但是bash可以执行echo和export命令,因此它们是内建命令

3. 本地变量

本地变量只有在本bash内部才有效,无法被子进程继承下去。只有将本地变量导成环境变量,才能被子进程继承

证明:

新建一个本地变量AAA并赋值为111

上图表明本地变量AAA不被认为是环境变量,所以不在bash的env中。但AAA还是在bash内部的。同样能证明,echo是内建命令,否则它不能访问只在bash内部才有效的AAA

修改.c文件

执行程序后,path=NULL,所以子进程不能看见并访问bash的本地变量

将本地变量导出成环境变量

此时AAA既在bash的env中,也可以被子进程看见并访问


好了,那么本篇博客就到此结束了,如果你觉得本篇博客对你有些帮助,可以给个大大的赞👍吗,感谢看到这里,我们下篇博客见❤️

相关推荐
€☞扫地僧☜€1 小时前
docker 拉取MySQL8.0镜像以及安装
运维·数据库·docker·容器
hjjdebug1 小时前
linux 下 signal() 函数的用法,信号类型在哪里定义的?
linux·signal
其乐无涯1 小时前
服务器技术(一)--Linux基础入门
linux·运维·服务器
Diamond技术流1 小时前
从0开始学习Linux——网络配置
linux·运维·网络·学习·安全·centos
写bug的小屁孩1 小时前
前后端交互接口(三)
运维·服务器·数据库·windows·用户界面·qt6.3
斑布斑布1 小时前
【linux学习2】linux基本命令行操作总结
linux·运维·服务器·学习
紅色彼岸花1 小时前
第六章:DNS域名解析服务器
运维·服务器
Spring_java_gg2 小时前
如何抵御 Linux 服务器黑客威胁和攻击
linux·服务器·网络·安全·web安全
✿ ༺ ོIT技术༻2 小时前
Linux:认识文件系统
linux·运维·服务器
会掉头发2 小时前
Linux进程通信之共享内存
linux·运维·共享内存·进程通信