️作者:@malloc不出对象
⛺专栏:Linux的学习之路
个人简介:一名双非本科院校大二在读的科班编程菜鸟,努力编程只为赶上各位大佬的步伐
环境变量(environment variables)一般是指在操作系统中用来指定操作系统运行环境的一些参数,如:临时文件夹位置和系统文件夹位置等。我们在编写 C/C++ 代码的时候,在链接的时候,从来不知道我们的所链接的动态静态库在哪里,但是照样可以链接成功,生成可执行程序,原因就是有相关环境变量帮助编译器进行查找。环境变量通常具有某些特殊用途,还有在系统当中通常具有全局特性。
下面我们将用./
切入我们的话题,为什么我们自己生成的可执行程序在当前路径下需要加./
才能运行起来呢?我们之前讲到过Linux下一切皆文件,在Linux中大多数命令都是用C语言编写形成的可执行程序,它们通常是二进制文件或脚本文件,那么为什么执行像ls
这样的指令时,我们不需要在前面使用./
呢?它也是一个可执行程序啊?
在Linux中,要运行一个可执行程序,需要在终端中输入可执行程序的名称,并在名称前加上"./"
,这是因为Linux系统默认情况下只会在一些特定的路径中查找可执行程序,而当前目录通常不在这些路径中。对于像"ls"
这样的系统命令,可以在任何目录中直接运行,而不需要在命令前加上"./"
,这是因为系统已经将这些命令的路径添加到系统环境变量中了。这些命令的路径通常在"/bin"、"/usr/bin"、"/usr/local/bin"
等目录中,这些目录已经被添加到系统环境变量的PATH
变量中了,所以在终端中输入这些命令名称时,系统会自动在这些目录中查找相应的可执行程序。
好了,想必通过./
这个切入点,我们已经明白了其实"./"
执行可执行程序,其实并不是规定要这样写的,它其实是在定位找到我们的可执行程序的所在位置,然后再执行这个可执行程序!!
如果我们也想在自己编写的程序中实现这种无需添加"./"的运行方式,直接先ls指令一样使用的话,我们可以将程序所在的目录添加到系统环境变量的PATH变量中,这样系统就可以在该目录中查找可执行程序或者你也可以将可执行程序复制到一个已经在PATH变量中的目录中,这样也可以直接运行该程序。
export 本地变量 #将已经定义好的本地变量导入到环境变量中
export 变量名=字符串 #将变量导入到环境变量中
错误导入方式
如何解决这种错误的导入路径的方式导致我们的大部分系统的指令不可使用的问题?
我们重新登录一下就恢复到默认的PATH环境变量了,这是很好的一种安全机制防止我们误操作修改环境变量导致某些问题的发生。
正确导入方式
export PATH=$PATH:自定义路径 # $PATH是原来默认的系统环境变量,我们用:将自定义的路径拼到后面,此时我们的PATH环境变量就多了这一条子路径了
另外我们还可以将mytest这个可执行程序拷贝到已经添加到PATH环境变量中的路径下,我们来试试看:
在Linux中把可执行程序拷贝到系统默认路径下,让我们可以直接执行该指令,它就相当于Linux中软件的安装,rm删除该可执行程序就相当于删除软件!!在windows中也一样,当我们下载安装某个软件时,是不是要默认指定放在哪个路径下,这个过程中可执行程序的数据就被拷贝到这个指定的路径下,然后我们双击就能够打开这个软件了;卸载也是同样的道理!!
我们在我们安装IDEA或者Pycharm时,为什么要重新手动配置PATH环境变量的原因?
这也是因为系统在默认路径下找不到它们,所以我们要手动将它们的路径添加PATH环境变量中!!这样下次我们就能直接打开它们了。
unset 环境变量 #清除指定的环境变量
unset 本地变量 #清除指定的本地变量
env # 查看全部的环境变量
这些环境变量采用的都是K—V模式,K对应环境变量,V对应环境变量的内容!!我们可以看到这些环境变量都有不同的作用,大家下来可以试试这些环境变量的作用,总之环境变量的内容也会随着环境的变化而变化。例如:当前登录名LOGNAME为curry,此时我的USER用户为curry,HOME为/home/curry,当我使用su/sudo切换用户时,此时某些环境变量的内容就发生了变化,USER用户为root,HOME为/root,所以我们的环境变量内容其实也是根据不同的场景来输出对应的内容的。
unset:清除指定的环境变量
unset清除后在env表中就找不到myval环境变量了
在切入这个问题之前,首先我们来看看我们最常使用的main函数,请问main函数有参数吗?
答案是有的,但是平时我们很少看见或者使用它的函数参数,这是为什么?这是因为即使我们不写,我们的系统调用main函数,对它进行传参会默认将它们加载进来,而且如果没有将这些参数我们的程序就编译不了,具体原因见下文分析。
我们的main函数最多有三个参数,下面我们先来讲解第三个参数char* envp[]。
char* envp[],envp它是一个数组,数组里面每个元素的类型为char*,在C语言中char*可以保存字符的地址,也可以保存字符串首字符的地址,在此时char*保存的是字符串首字符的地址:
我们运行程序看看envp数组里面存的是什么:
我们发现envp数组里面存的内容跟env指令显示出的内容一致,这就说明了envp数组里面存的字符串对应的是一个一个的环境变量,由此当我们使用main函数时,实际上无论何时都使用了环境变量去指定的路径下搜索来完成我们特定的功能!!
envp是一个环境变量表!! 每个程序都会收到一张环境表,环境表是一个字符指针数组,每个指针指向一个以’\0’结尾的环境字符串。
下面我们来看看另外一种获取环境变量的方式:
我们使用一个二级指针environ指向环境表的首地址,实际上使用char* envp[]和char** environ是一样的,因为数组在传参的时候会发生降维,降维成指向对应类型的指针。
对于这两种的获取环境变量的方式,我们需要遍历去寻找对应的环境变量,这样是非常不方便的,所以Linux提供了一个获取环境变量的函数,它是按照K—V的模式找到环境变量输出相应的内容的。
如果我们想对文件做某种限制,我们只想要当前用户能够访问这个文件,而其他用户不能访问该文件,我们就可以采取下面的措施:
通过这个例子我们可以知道,实际上我们对文件做某种操作是先要根据它的用户来进行判断的,如果是当前用户就根据文件权限来判断它是否具有某种能力,如果是其他用户那么要按照其他组的权限来判断它是否能对该文件做某种操作!!所以USER这个环境变量其实是非常重要的。
下面我们来自己实现与pwd的功能一致的指令,其实它本质上就是根据环境变量来进行实现的
通过上诉一系列的讲述,下面我们再来重新深入理解一下环境变量:
我们通过在命令行上自定义变量来切入这个话题:
特性:环境变量通常具有全局属性,可以被子进程继承下去。
下面我们继续来看一个例子:
那么问题来了,echo不也是一个指令嘛?在Linux中大多数指令都是可执行程序,那么请问echo为何能读取hello1变量的内容??
我们换种思路想,也许echo根本就不是可执行程序呢,它的父进程不是bash,这样也就能解释的通echo能打印hello1变量的内容了。其实echo它是一个内建指令(内置指令),这些命令在执行时不需要调用外部可执行文件,而是由shell程序自己直接处理。这样可以提高命令的执行效率和响应速度,并减少与外部可执行文件的交互次数。关于内置指令后续我们再来谈及这个问题。
下面我们通过main函数的第一二个参数来切入我们的话题:
那么命令行参数到底有什么用呢?
在上述图中我们可以看到通过不同的参数选项,我们展示了同一个程序的不同执行结果!!
命令行参数最大的意义就是根据选项的不同,让程序执行不同的任务和功能。
本篇文章的内容就讲到这里了,如果对于本文有任何问题或者错处欢迎大家评论区相互交流orz~