目录标题
- 指令的本质
- 如何不加./
- 方法一
- 方法二
- 环境变量的重置
- 在命令行上查看环境变量
- 为什么会存在环境变量
- 在程序中查看环境变量
- 本地变量和环境变量
- 环境变量的继承
指令的本质
在使用linux的时候我们经常会使用很多指令比如说:ll指令,pwd指令,whoami指令等等,不同的指令都对应着不同的功能:
我们平时也会写一些c语言文件,再通过gcc编译器将这些文件生成一个可执行程序,比如说这里的myproc.c文件这个文件里面就写着一些c语言代码:
myproc是一个可执行程序这个程序是由文件myproc.c编译生成的,并且这个程序运行的结果就是不停的打印这个进程的PID是多少方便我们执行其他的操作:
那这里能不能换个方式来描述一下myproc可执行程序,我们说这个程序的功能是循环打印处本进程的PID,如果这么描述的话大家有没有发现一些相似之处,我们说执行不同的指令就是执行不同的功能,而运行可执行程序也是执行对应的功能,那我们能不能说平时使用的指令就是一个个的可执行程序呢能不能平时我们写的可执行程序也是一个指令呢?答案是可以的我们通过file指令就可以看到平时使用的指令都是可执行程序:
但是这里就有一个问题:我们写的文件是可执行程序,操作系统自带的指令也是可执行程序,那为什么运行自己写的可执行程序的时候得在前面加上./
而系统中的指令却不用呢?原因很简单当我们在操作系统上执行可执行程序的时候得告诉操作系统这个程序在哪里,而./
就是告诉操作系统你要执行的程序就在当前路径下,如果我们将当前的路径进行修改改成上一层路径再想执行myproc程序的话就不能使用./myproc
而是./folder2/myproc
执行操作系统内部的指令之所以不用添加路径是因为系统中定义了一个全局变量PATH,这个变量里面记录了内部指令所在的路径当我们运行可执行程序没用添加路径的时候,系统就会默认在PATH记录的地址中去寻找并执行该程序,我们可以通过echo $PATH
指令来查看PATH变量记录的值:
仔细观察一下就可以看到这个变量记录了多个地址并且不同的地址通过:进行隔开。
如何不加./
方法一
不加路径执行程序的时候操作系统会在PATH记录的默认路径下查找对应的程序,那如果我们把自己写的程序添加到PATH所指向的路径之一的话,那我们在执行该程序的时候是不是就不用添加相对路劲了呢?我们来看看下面的操作
这里执行失败是因为将程序拷贝到那个路径下得提权普通用户是没用权限的,我们再来操作一次:
就可以发现myproc程序不添加相对路径也可以正常执行,但是这种方法不推荐大家使用因为你写的程序不一定安全将不安全的程序添加到这些路径下可能会存在风险,所以我们一般采用第二种方法。
方法二
方法一是将程序添加到PATH里面的路径中,那么方法二就是将该程序所处的路径添加到PATH变量里面,但是这里大家要注意一点将程序的地址添加到PATH变量里面是指令export PATH=$PATH:/程序所在的路径/
而不是export PATH =/程序所在的路径/
,因为第二个方法所造成的的结果是让PATH的值变成了你的路径,而不是将你的路径添加上去比如说下面的操作:
而使用第二种指令之后变量PATH的内容会被你添加的地址所覆盖:
那么这里大家要注意一下。
环境变量的重置
如果大家在命令行中一不小心将环境变量的内容修改了的话,请大家不要慌因为你重新登录一下就可以发现之前修改的环境变量又变回了之前的值,比如说上面修改了环境变量PATH但是重新登录一下就可以看到PATH的内容被复原了
这是因为在家目录下有这.bash_profile和.bashrc这两个文件
打开.bash_profile文件可以看到下面的内容
我们来看看下面这段代码
if [ -f ~/.bashrc ]; then
. ~/.bashrc
这段代码是一个shell脚本,-f ~/.bashrc
的意思就是检测.bashrc文件是否存在,如果存在的话就执行下面的代码:
~/.bashrc
这段代码的意思就是执行.bashrc文件里面的内容,在这个文件的下方还有一段代码就是:
PATH=$PATH:$HOME/.local/bin:$HOME/bin
export PATH
这段代码干的事情就是创建环境变量PATH并往这个变量里面导内容,我们再打开.bashrc文件
就可以看到这个文件里面也会检测系统的bashrc文件是否存在,如果存在的话就会执行这个文件同时在这个文件的下方也会创建环境变量和导环境变量,我们打开系统的bashrc文件看看里面有什么内容:
我们看到这个文件里面有非常多的内容,但是这么多内容他的目的却只有一个就是帮我们创建环境变量并导环境变量,这个文件的内容大家肯定是看不懂的,但是大家得知道一件事就是每次登录用户的时候操作系统会自动地执行.bash_profile文件里面地内容,在.bash_profile文件里面会创建并导一些环境变量然后在执行.bashrc文件里面地内容,在.bashrc文件里面会创建并导一些环境变量然后执行系统的bashrc文件里面的内容,而系统的这个文件里面也会执行其他文件的内容并创建一些环境变量,所以我们每次登录用户时环境变量都会被重新创建并初始化为一个固定值,希望大家可以理解。
在命令行上查看环境变量
使用指令env
就可以查看所有的环境变量;
其中环境变量HOME就是记录当前用户的家目录:
环境变量HOSTNAME就储存着主机名
环境变量HISTSIZE中就记录了操作系统所能记录的最大历史指令数为3000
当然这里的环境变量还有很多这里我们就不一一介绍大家可以自行了解。
为什么会存在环境变量
大家有没有想过一个问题:在命令行上输入pwd指令为什么会显示程序当前所在的路径?输入whoami指令的时候linux怎么知道当前使用登录机器的用户是谁?在命令行输入指令的时候linux为什么能够知道这些指令所在的位置在哪里?linux怎么知道你当前使用的shell种类是什么?linux怎么知道当前的各种配置方案所用的编码方式是什么?记录历史指令的最大指令条数是什么和各种动静态库头文件的搜索路径在哪?等等问题上面问题涉及着Linux的不同的领域,有的涉及着查找指令的,有的涉及登录用户是谁的,有的是确认登录主机名是谁的,有的是确认使用shell种类的,那么为了解决上面各种各样的问题,操作系统就得在启动bash的时候给我们做命令行解释解释器的时候设置好一批未来要用到的全局变量,这批变量我们就将其称之为环境变量,环境变量是操作系统为了满足不同的应用场景预先在系统内设置的一大批的全局变量,这些变量在整个系统当中从bash往后都会被其他的进程所访问到,不同的环境变量都有着它不同的用途,比如说环境变量HOME就是记录着当前用户的家目录所以在命令行上使用cd ~的时候可以直接将当前路径切换到家目录下,cd ~就直接变成了cd HOME,环境变量HOSTNAME储存着主机名所以Linux可以知道当前使用机器的主机名,环境变量PWD时时刻刻记录着的当前所在路径所以在使用pwd指令的时候可以在屏幕上显示当前所在的路径,那么这就是环境变量存在的意义它可以帮助操作系统解决一些不停领域上的问题。
在程序中查看环境变量
在命令行上可以通过指令env来查看有哪些环境变量以及环境变量的内容,那么在我们写的程序里面也可以通过函数getenv来获取你指定的环境变量,我们来看看这个函数的功能介绍:
该函数的参数是一个字符指针返回值也是一个字符指针,如果你先查看环境变量PWD的内容的话就可以使用getenv函数并把字符串"PWD"传给这个函数,该函数就会返回一个指向环境变量的内容的指针,比如说下面的代码:
这段代码的运行结果如下:
如果我们想查看环境变量USER的内容的话就可以把字符串"USER"传递给这个函数:
这段代码的运行结果如下:
当然这里只是该函数的一个使用方面将内容打印到屏幕上面,我们还可以使用该函数在程序里面实现其他的功能,比如说当前的程序可以打印出来使用者的名字:我们当前的用户是xbb所以打印出来的是xbb,
如果我们切换成其他的用户再执行这个程序的话打印出来的结果也就是其他用户的名字,按下ctrl+D先退出当前用户再重新登录一下就可以看到当前的用户变成了root:
也就是说不同的用户执行同一个程序会有不同的结果,原因就是用户所对应的环境变量的内容是不一样的,那这里大家想一下之前学习的权限,我们说不同的人有不同的权限,没有权限的人是无法查看或者使用或者修改别人的文件,那这里的权限不就通过环境变量来实现的嘛?通过getenv函数可以得到环境变量USR的内容,而不同的用户所对应的环境变量的内容又是不一样的,那如果这个文件只想让root用户运行的话是不是就可以使用getenv函数加if语句的形式来实现这里的权限,比如说下面的代码:
当前的用户是xbb所以这个程序执行的结果就是告诉我们没有权限
如果我们将用户修改成root,那么这个程序就可以正常执行:
那么这就是getenv函数的作用希望大家能够理解。
本地变量和环境变量
我们可以在命令行上定义环境变量比如说下面的操作:
并且还可以通过echo指令显示这个环境变量的内容:
但是这里虽然能够通过echo显示这个环境变量的内容,但是我们env指令却找不到这个任何关于myval的内容:
之所以出现这样的现象是因为通过该方式创建的变量不是环境变量而是本地变量,本地变量只能在当前进程中使用在其他进程中是无法使用的,就好比c语言中的全局变量和局部变量。通过指令set可以查看所有的环境变量和本地变量,由于本地变量的内容非常的多所以使用set指令的时候一般搭配着grep指令一起使用,比如说下面的操作:
使用export指令可以将本地变量的内容导到环境变量里面去该指令的使用形式为:export + 本地变量名
比如说下面的操作:
当然也可以使用export指令直接创建环境变量:
如果想要删除环境变量里面的本地变量的话就可以使用指令unset其形式为:unset 变量名
比如说下面的操作:
当然使用这个指令也可以删除本地变量比如说下面的操作:
环境变量的继承
我们在上面说过环境变量具有全局属性在所有的进程中都可以使用,而本地变量没有全局属性只能在当前进程中被使用,就好比c语言中的全局变量和局部变量那我们这里我们可以通过下面的操作来证明这一点:首先创建一个环境变量myval和一个本地变量myval1:
因为如果使用getenv函数没有找到对应的环境变量的话就返回一个空指针,所以我们可以根据这个函数的返回值来写一段下面的函数:
在命令行执行一个程序本质上是创建一个子进程让子进程来完成这个程序,环境变量的内容是全局变量所以在子进程中可以被使用,而本地变量的内容不是全局变量所以子进程中是无法打印出本地变量的值的所以这段代码的运行结果如下:
那这里就有个问题环境变量是如何做到全局属性的呢?为什么要有全局属性呢?原因很简单我们知道bash是一个系统进程,我们执行的myproc程序会通过fork函数变成bash的子进程,而全局变量之所以具有全局属性是因为bash的环境变量会被子进程继承下去,所以这也是为什么myval可以在子程序myproc中找到而myval1却找不到的原因,那为什么子进程要继承父进程的环境变量的原因呢?答案是为了不同的应用场景比如说让bash帮我们找指令的路径,身份认证等等等,这些都是要继承环境变量的原因希望大家能够理解。