公司网站的设计规划,金华网站建设团队,私人订制app,mysql网站后台管理系统下载文章目录 1. 环境变量的基本概念2. 如何理解呢#xff1f;#xff08;测试PATH#xff09;2.1 切入点1查看具体的环境变量原因剖析常见环境变量 2.2 切入点2给PATH环境变量添加新路径将我们自己的命令拷贝到PATH已有路径里面 2.3 切入点3 3. 显示所有环境变量4. 测试HOME5. … 文章目录 1. 环境变量的基本概念2. 如何理解呢测试PATH2.1 切入点1查看具体的环境变量原因剖析常见环境变量 2.2 切入点2给PATH环境变量添加新路径将我们自己的命令拷贝到PATH已有路径里面 2.3 切入点3 3. 显示所有环境变量4. 测试HOME5. 通过代码如何获取环境变量5.1 main函数的第三个参数环境变量表5.2 通过全局变量environ获取 6. 环境变量的组织方式7. 通过系统调用获取环境变量8. 再来理解到底什么是环境变量9. 环境变量通常具有全局属性可被子进程继承10. 环境变量与普通变量11. 命令行参数的理解 我们在学校学习某些编程语言比如Java、python一开始在配置环境的时候基本上都会做一件事情就是配置环境变量。 那我们当时往往都是按照老师的指导或者跟着网上的一些教程直接就把它配置了但是我们可能并不明白配置这个环境变量到底是干啥的它到底有什么作用 那这篇文章我们就来谈一谈环境变量到底是个什么东西
1. 环境变量的基本概念
首先我们可以来看一下环境变量的概念 1. 环境变量(environment variables)一般是指在操作系统中用来指定操作系统运行环境的一些参数 如我们在编写C/C代码的时候在链接的时候从来不知道我们的所链接的动态静态库在哪里但是照样可以链接成功生成可执行程序原因就是有相关环境变量帮助编译器进行查找。 2. 环境变量通常具有某些特殊用途还有在系统当中通常具有全局特性 单凭这段文字大家肯定还不能理解到底什么是环境变量那下面我们通过几个问题来帮助大家理解
2. 如何理解呢测试PATH
2.1 切入点1
我们之前在Linux上写过C程序并且我们知道如何编译链接让它生成可执行程序然后运行它。
比如 我写了这样一个test.c 并且写好了Makefile。 然后我执行make命令就生成了对应的可执行文件 然后我运行一下 没什么问题。 但是呢我想问大家一个问题为什么我们运行这样的可执行文件要加上./呢 那我问大家我们写的.C的文件生成的可执行程序我们可以像指令那样去执行它来完成相应的任务。 那这个可执行程序可以叫做指令嘛 我记得在刚开始我们学习Linux基本命令的时候就有说过 指令其实也是文件可执行文件 我们可以file查看一下我们平时常用的命令比如——ls 我们看到它其实就是一个可执行executable程序啊 那我们这里自己生成的可执行程序myproc呢 我们看到它们其实就是一样的没什么区别。 只不过人家写的ls这些指令被纳入了Linux的基本指令里面而我们写的只能自己玩玩。但他们本质上都是可执行程序。 但是呢问题就来了为什么我们运行ls这些指令可以直接敲对应的指令直接执行而我们自己生成的可执行程序运行要加./呢
为什么呢 如果我想让我们自己的可执行程序也可以不加./直接运行能做到吗如何实现呢 ./我们知道它是啥东西.代表当前目录嘛/是路径分隔符嘛。 那我们这里的可执行文件myproc就是当前目录下的一个文件 所以执行我们自己的可执行程序好像必须要定位到它所在的路径。 那上面./的定位方式其实是相对路径那用绝对路径是不是也可以执行这个可执行文件 这当然也是可以的。 但是它为什么就不能像ls哪些基本命令那样无需指明路径直接执行呢 那原因呢其实就在于像ls这些基本指令系统中原本就存在与之相关的环境变量。我们执行这些指令的时候系统会自动根据环境变量去相对应的路径下查找这些指令能够找到就可以直接执行而无需指明完整路径。 所以执行一条指令的前提是得先找到它。 那么Linux中就存在这样一个环境变量——PATH PATH 用于指定命令的搜索路径 我们可以先查看一下它
查看具体的环境变量 echo $NAME //NAME环境变量名称 原因剖析
那么上面说了这么多为什么ls哪些基本直接无需指明路径就可以直接执行而我们自己的可执行程序不可以呢 那原因就在于我们在命令行执行ls这些基本指令的时候系统会自动去环境变量PATH中指定的这些路径里面查找如果能找到对应的指令就可以执行无需我们自己指明具体路径。 而我们自己的可执行程序 所在的路径是没有包含在PATH环境变量定义的路径里面的。 所以运行的时候我们必须自己指明路径如果没有指明那么系统就找不到该命令无法去执行 那这里我们提到的PATH其实就是一种环境变量
常见环境变量 PATH : 指定命令的搜索路径 HOME : 指定用户的主工作/家目录(即用户登陆到Linux系统中时,默认的目录) SHELL : 当前Shell,它的值通常是/bin/bash 那到这里大家再去回看最开始环境变量的概念以及后面跟的例子 环境变量(environment variables)一般是指在操作系统中用来指定操作系统运行环境的一些参数 如我们在编写C/C代码的时候在链接的时候从来不知道我们的所链接的动态静态库在哪里但是照样可以链接成功生成可执行程序原因就是有相关环境变量帮助编译器进行查找。 相信大家可能就有一点感觉了。
2.2 切入点2
那如果我想让我们自己的可执行程序像ls这些基本命令那般可以直接执行而无需指明路径应该怎么实现呢 那经过上面的学习我们知道为啥我们自己的可执行程序不能直接运行而需要指明路径啊不就是因为我们自己的可执行程序没有在PATH环境变量定义的路径里面嘛。 那所以呢 如果我们想要我们自己的可执行程序可以像ls这些基本命令那样直接执行是不是把我们自己的可执行程序所在的路径添加到PATH环境变量里面就行了。 给PATH环境变量添加新路径
那如何添加呢 export PATH$PATH:要添加的路径修改PATH环境变量添加一个新的路径 export可新增修改或删除环境变量 我们来试一下 我们把myproc的路径添加到PATH里面 那现在我们再来执行我们自己的可执行程序myproc 我们发现就可以直接执行而无需再指明路径了。 另外需要注意的是如果这样写的话 这样就不是添加而是修改PATH里面的路径了这样修改后PATH里面就只有这一条路径了。 那你的ls这些基本命令可能就无法执行了。 但是如果这样做了也没关系关闭你的Xshell重新登录就恢复了。 当然同样的我们添加之后后面重新登录的话它其实也会恢复。 将我们自己的命令拷贝到PATH已有路径里面
那除此之外大家想一下还有没有其它的方法可以使我们自己的可执行程序能够不带路径直接执行呢 我们如果把我们自己的可执行程序放在PATH环境变量里面已包含的路径里面按理说应该也可以啊。 我们试一下 我新打开一个渠道 现在执行myproc是不行的。 那我们现在把myproc拷贝到PATH里面已有的路径比如usr/bin/下面 拷贝好了。 那我现在把当前目录下面的这个myproc删掉 然后我现在像执行ls那样直接执行myproc 是可以的并且我们which命令也可以查到。 那像我们上面这样 在Linux中把可执行程序拷贝到系统环境变量默认路径下让我们可以直接访问的方式——其实就相当于Linux下软件的安装。 那如果我不想要它了把他从对应路径里面删掉 就用不了了那这其实就相当于卸载。 2.3 切入点3
我们在Linux上用不同用户登录的时候系统中也会有对应的环境变量来记录当前登录的用户是谁 这个环境变量呢就叫做——USER 我们可以来查看一下它 我当前登录的用户是yhq那我查看这个环境变量就是yhq 如果我切换成root 查看到就是root 然后大家再来思考一个问题 前面我们讲文件权限的时候我们要判断一个用户对某个文件是否拥有某些权限的时候一般首先我们要定位一下该用户的角色它是这个文件拥有者还是所属组或者other。 那么系统是如何知道当前用户是什么角色呢 那就是因为有环境变量的存在。 当你登录的时候环境变量就记录了你是哪个用户 所以当我们访问某个文件的时候那系统就可以拿着你当前的用户名和文件的拥有者、所属组或other进行对比从而就能判断出来你是什么角色然后拿对应的权限去套你以此来确定你对某个文件拥有哪些权限。 所以这种情况也是依靠环境变量来处理的。 3. 显示所有环境变量
那如果我想查看我这个用户当前系统上所有的环境变量都有哪些要如何查看呢 这里用到的命令叫做——env列出所有环境变量及其赋值 它就列出了当前系统上我这个用户所有的环境变量这些环境变量基本上都是我们登录的时候就设定好的。 比如 挺多的大家感兴趣可以自己查询了解一下。 4. 测试HOME
上面我们提到过一个环境变量——HOME HOME : 指定用户的主工作/家目录(即用户登陆到Linux系统中时,默认的目录) 那当前我是普通用户我们查看HOME环境变量的话 显示的值就是我的家目录 那如果我切换成root 那我们再查看就是root的家目录。 所以对于同一个环境变量如果对应的用户不同那它的值可能就是不一样的。 5. 通过代码如何获取环境变量
上面我们提到系统启动的时候就已经存在大量的环境变量那如果我们想获取到这些环境变量要怎么做呢 那我们其实是可以自己写一个程序来获取的 5.1 main函数的第三个参数环境变量表
那首先来问大家一个问题大家之前肯定都写过C/C的程序那我想问大家的是main函数可以带参数吗如果可以的话最多可以带几个呢 我们平时自己写C/C代码一般写的main函数都是无参的 但是呢相信大家可能会在网上或者一些书籍上见过带参数的main函数比如这样的 最常见的就是这种两个参数的如果这两个参数你不知道是啥没关系我们后面也会给大家介绍。 但是呢main函数其实是可以有3个参数的 那我们先来讨论一下这个第三个参数——envp通常我们把它叫做环境变量表。 我们再来看第三个参数大家说 char* envp[] 这是个啥啊 这不是一个字符指针数组嘛。 每个元素都是一个char*的指针那这些指针都指向什么东西呢 我们学过C语言对于一个字符指针来说它指向的内容无非就两种 指向一个字符即存储一个字符变量的地址指向一个字符串即存储的是一个字符串的首字符地址 那在这里我明确的告诉大家它指向的就是一个字符串并且 char* envp[]这个字符数组的最后一个元素里面一定存的是NULL当然其实不一定总是最后一个元素应该说第一个无效元素存的是NULL。 比如该数组大小为10只有前5个元素都指向字符串那么它第六个元素就指向NULL。 那它指向的字符串是什么呢 不知道没关系那我们可以遍历envp数组打印出来看一下 我们来运行一下看看这个表里面存的到底是啥 大家看看这打印出来的是啥啊 这不是跟我们之前用env命令列出的环境变量一样嘛只不过我们在前面加了下标这些信息。 其实不用打印我们也能猜出来我们说了它是环境变量表嘛所以它里面放的就是一个一个的环境变量以及它们对应的值组成的字符串。 5.2 通过全局变量environ获取
那么除了上面的方法我们还可以通过一个全局变量来获取环境变量 这个全局变量叫做——environ 我们可以来查看一下 我们看到它的类型是char**是一个二级指针类型 那char**的话其实跟上面的char* envp[]不是一样嘛 因为char* envp[]是在main函数的参数列表里面那传参的话传一个数组传过去的真正是啥是不是数组首元素地址啊。 char* envp[]首元素是char*那首元素的地址不就是char**的二级指针嘛。 所以同样的environ也指向环境变量表。 那我们就来用environ打印一下环境变量表 那其实跟上面用char* envp[]的方式是一样的 我们来运行一下 效果是一样的。 libcLinux下的ANSI C的函数库中定义的全局变量environ指向环境变量表environ没有包含在任何头文件中所以在使用时 要用extern声明。 那么由此我们也引出——环境变量的组织方式
6. 环境变量的组织方式 每个程序都会收到一张环境变量表环境变量表是一个字符指针数组每个指针指向一个以’\0’结尾的环境字符串即环境变量名及其值组成的字符串 7. 通过系统调用获取环境变量
上面呢我们已经介绍了两种通过代码获取环境变量的方式但是 我们以后如果要获取某个环境变量比如PATH的时候难道要像上面那样遍历指针数组环境变量表再通过字符串匹配去一个个找吗 可以是可以但是好像有点麻烦那有没有更简便的方法呢 当然是有的除了上面介绍的两种方式我们还可以通过函数系统调用直接获取指定的环境变量。 那我们下面就来学习一下 首先用来获取特定系统变量的函数——getenv 那它是如何使用的呢 我们可以打开man手册来看一下man getenv 需要包含的头文件是stlib.h 该函数的返回值是char*一个参数const char *name 所以我们调用时传入指定的环境变量名就可以获取到该环境变量 如果没有匹配到 返回NULL 那我们可以来写个代码试一下 比如我们获取一下环境变量USER 我们来运行一下 就成功获取到了我们当前系统上环境变量USER 的值。 那其他的也是一样我们调用getenv传对应的环境变量名称就行了。 8. 再来理解到底什么是环境变量
那讲到这里我们再回过头来理解一下到底什么是环境变量 那在上面的学习中我们了解了环境变量的概念也进行了一些实操。 比如我们把自己写的可执行程序的路径添加到了PATH环境变量中使得我们运行自己的可执行程序时可以像基本命令ls那样无需指定完整路径直接可以运行。 但是呢我们同时也注意到一个问题就是我们如果重新登录的话环境变量PATH里面的路径就被重置了我们再去直接运行我们的可执行程序就不行了除非你再次添加。 那这说明了什么呢 上面我们获取了环境变量我们知道它其实就是一张表嘛。表里面包含了所有的环境变量以及它们对应的值键值对集合。 那上面我们提到的现象又说明了什么呢 它说明了环境变量其实本质是一张内存级的表在用户登录的时候就会由系统去特定用户形成属于自己的环境变量表。 而表中的每一个环境变量都有自己特定的应用场景比如有的是指定命令搜索路径的有的是进行身份验证的等等。 表中的每一个环境变量都是KV的键值对形式。 那再来思考一个问题 我们说环境变量是一张内存级的表用户登录时由系统形成。那么表中的数据都是从哪来的呢 表中的环境变量信息呢其实都是从系统的相关配置文件中读取进来的。 那这些配置文件又在哪里呢 我们进入用户的家目录在家目录下面呢我们能找到这样两个文件 它们其实是两个shell脚本。 那打开的话其实我们现在也看不太懂 但是它们里面其实就是对环境变量进行设置啥的这样一些操作。 当我们每次登录成功的时候系统会重新读取配置文件把这些配置文件中的脚本执行然后就自动形成对应的环境变量加载到内存中。 9. 环境变量通常具有全局属性可被子进程继承
上面我们提到环境变量其实是一张内存级的表 那这张表其实是在shell内部由shell来维护的那我们知道Linux上的shell一般是bash我们在命令行启动的所有程序通常都是bash的子进程。 然后呢在上面我们学过一个命令——export export可以新增修改或删除环境变量。 上面我们使用export对PATH环境变量进行了修改。 那我现在想新增一个环境变量怎么做呢 export VARIABLE_NAMEvalue 其中VARIABLE_NAME是要新增的环境变量的名称value是环境变量的值 我们来试一下 我新增了一个环境变量为helloyoucanseeme 那我们知道所有的环境变量都在环境变量表里面存放那我们在环境变量表里面是不是能查看到我们新增的这个环境变量呢 那我们使用env命令列出所有环境变量及其赋值 那在显示出来的环境变量表中我们就看到了刚才我们自己添加进行的环境变量表。 上面我们说到 环境变量表是在bash中由bash维护的所以我们执行export VARIABLE_NAMEvalue命令之后。 那bash就会把这个环境变量及其赋值作为一个字符串添加到环境变量表的指针数组中。 然后呢想告诉大家的是 经过之前的学习我们知道命令行启动的程序都是bash的子进程而环境变量——环境变量通常具有全局属性可以被子进程继承下去 那我们能不能证明一下呢你说环境变量可以被子进程继承那就真的是这样吗 那我们来写这样一个程序 我们刚才不是新增了一个环境变量嘛那我们现在来获取一下它如果获取到了打印一下。 来试一下 我们成功获取到了刚才新增的那个环境变量。 那这能证明什么呢 这个结果不就证明了环境变量被子进程继承下来了嘛。 因为我们在命令行启动的这个程序是bash的子进程啊而我们上面新增的子进程是在bash里面新增的而现在子进程获取到了它那也就证明环境变量被子进程继承了下来。 10. 环境变量与普通变量
我们来做一个实验 我们知道export VARIABLE_NAMEvalue可以新增环境变量到环境变量表里面。 那如果我不加export呢 比如 另外我们发现这样的话这个hello1也可以像环境变量那样打印 那它也可以通过子进程获取到嘛我们来试一下 现在我们用getenv来获取hello1 我们来运行一下 我们发现啥也没有那就是没有获取到返回的是NULL 那所以呢带export和不带export有什么区别呢 我们知道带export的话它就会把后面的变量及其赋值当作环境变量导入环境变量表中我们在环境变量表中可以查到并且它可以被子进程继承。 那不带export呢 通过上面的实验我们知道它不会被子进程继承那就说明它不是环境变量但是我们可以像查看环境变量那样查看到它那就说明它也被bash记录下来了但是它没有被添加到环境变量表中成为环境变量。 所以不带export的这种变量我们把它叫做shell的本地变量或者叫普通变量它就不具有全局属性而是局部有效只在shell内部有效。 但是如果我后续就是想让这个hello1这个普通变量能够被子进程继承怎么办呢 那也很简单你就再用export把它导进去环境变量表就行了 然后我们看到就可以了。 但是这里好像还有一点问题值得我们思考 这样不加export他就是一个普通变量也会被bash记录下来。 我们也可以用echo $变量名打印它的值只是它没有被添加到环境变量表里面子进程不会继承获取不了。 但是你不觉得奇怪吗 我们执行echo $hello2这也是一个指令啊那按理说他也是bash的子进程啊但是本地变量不是不会被子进程继承吗可是为什么这里我们能够打印出来呢 那这个问题我们先放一放后面再说大家有兴趣可以自己先去研究思考一下。 那么以上就是环境变量的全部内容…
不过还有一个东西也值得我们来说一下
11. 命令行参数的理解
上面我们提到过 main函数呢其实是可以有3个参数的前面我们重点介绍了第三个参数char* envp[]。 那么下面我们来介绍一下前两个命令行参数int argc, char* argv[] 它们叫做命令行参数 那它们有什么用呢 首先呢这个argv[]我们看到它的类型和我们上面提到的环境变量表的类型是一模一样的是一个char*的指针数组。 argv[]也是一张表只不过内容肯定和环境变量表是不一样的。 那么第一个参数argc又是啥呢 他其实就是argv这个指针数组的大小。 那他里面到底放的是啥呢我们可以直接遍历这个数组打印看一下 我们来运行几次大家看一下现象 大家看看现在是否对命令行参数这几个字有一点感觉了 我们在调用这个程序的时候在命令行输入的这些内容 在shell看来就是一个字符串那么按照空格将其分割成子串 它们分别对应 那说到参数选项相信大家应该不陌生我们之前学习基本命令的时候很多命令后面都可以跟对应的选项 那此时我们再来讨论argv这个表里面存的是什么 那其实存的就是我们在命令行输入的字符串以空格分隔出来的一个个子串 bash通过命令行输入的字符串生成了这张表我们子进程里面可以用这个表。 如果我们每次把argc也都打印出来的话 再来运行几次 我们发现argc就是子串的个数也是指针数组argv的大小。 那这就是命令行参数那它有什么用呢
那下面我们来做一个实验 我们来尝试写这样一个程序 就是你调用我这个程序的时候必须带选项如果你第一次调用不知道的话没有带选项就打印提示然后根据提示你带不同的选项就会打印不同的语句代表完成不同的任务。就像我们的基本命令后面跟不同选项一样 所以我来写这样一个代码 我们来运行一下看看效果 那大家看这就是命令行参数的意义。 现在我们再来想我们之前学习基本命令的时候为什么我们跟不同的选项就对应不同的功能那其实就是通过命令行参数来实现的。