文章目录
环境变量
基本概念
环境变量(environment variables)一般是指在操作系统中用来指定操作系统运行环境的一些参数如:我们在编写C/C++代码的时候,在链接的时候,从来不知道我们的所链接的动态静态库在哪里,但是照样可以链接成功,生成可执行程序,原因就是有相关环境变量帮助编译器进行查找。
环境变量通常具有某些特殊用途,还有在系统当中通常具有全局特性。
常见环境变量
PATH : 指定命令的搜索路径
HOME : 指定用户的主工作目录(即用户登陆到Linux系统中时,默认的目录)
SHELL : 当前Shell,它的值通常是/bin/bash。
测试PATH
这个myprocess程序可以被理解成命令,
我们file myprocess
发现:
当前我们自己写的myprocess,它就是一个executable表示的是一个可执行程序。
继续输入:file /usr/bin/ls
file系统命令
发现也是64位下的可执行程序。
我写的可执行程序和系统里的可执行程序都是可执行程序。
为什么在执行指令的时候不用带./
路径,而运行myprocess要带./
路径?
因为我们要执行一个程序前提是先找到这个程序(指令),我们在运行程序的时候输入./myprocess
,这个./
叫做当前路径即可以帮我们找到程序。当我们程序运行指令ls
的时候直接就能跑的原因是系统帮我们默认找了。
如果我们想运行我们的程序但是不带任何的路径,那么可以sudo cp myprocess /usr/bin/
把myprocess拷贝到usr/bin对应的路径下,也就是把我们的程序拷贝到系统安装指令的路径当中。接下里运行就可以了:
但是不建议这么干,因为我们写的代码没有经过测试,尽量不要安装进去,会污染指令池的。
为什么我们cp指令过去系统就能找到呢?原因是系统中存在环境变量,path环境变量:操作系统在启动的时候会在shell上下文中定义的一个path变量,这个在系统全局有效。无法直接查看,必须加$
,
所以我们系统在执行指令时,会默认在每一个冒号作为间隔的每一条路径当中去帮我们检索,去搜索对应的指令,如果指令存在的话就找到并执行。搜索完所有的路径后发现指令不存在就报错。
我们系统中的指令可以执行是因为系统的指令是在user/bin这个路径下,能被系统找到,我们现在想让我们自己的指令执行的时候可以不带./
,我们可以这样操作:
将当前的路径加到环境变量当中这是一种属于内存级的环境变量。
然后我们再去执行就不用./
了。
which
指令在底层实现的时候,就是根据环境变量PATH,来进行路径搜索帮我们找要执行的指令。所以which
可以查自己的指令也可以查系统的指令。
bath 是可以定义变量的,$a
这个a的变量值便有了。
在windows下同样存在环境变量,
windows操作系统内部也有自己的变量的值,所以我们在配置Java等的时候可能要该path,添加一些东西。
cd ~
,进入当前用户的工作目录,
然后ls -al
,在我的家目录下存在两个文件,一个是.bash_profile
一个是.bashrc
,
我们打开.bash_profile
:
发现它做的是倒环境变量。同样我们打开bashrc
它会检查系统的bashrc
这个文件是否存在,如果存在也会倒环境变量,
然后我们可以vim /etc/bashrc
打开系统的bashrc
,它里面有很多的动作,就是在帮我们构建环境变量。我们就明白了一个道理:我们的shell在我们自己登录的时候,系统会默认让我们当前的shell进程把对应的.bash_profile
里面的内容执行一次,也就是把对应的环境变量倒到我们当前的shell当中,那么环境变量的配置就是通过.bash_profile
在启动的时候被加载倒bash当中,所以我们自己一旦启动成功后,在内存中会给我们维护一个变量叫作:$path
(内存级的),即使被覆盖掉也没关系,下次重新登陆时bath会重新去读取配置文件,把环境变量倒回来,这种变量是由操作系统为我们提供的,是具有全局属性的,往往具备特殊功能的变量,我们称为环境变量。
别的环境变量
除了path之外还有别的环境变量:
echo $ hone
:表示的是当前用户自己的工作目录。
ehco $ HOSTNAME
:表示的是主机名。
echo $LOGNANME
:当前登录系统的用户是谁。
echo $HISTSIZE
:系统可以记忆历史命令的最大值。
如果我们想查看系统中所有的环境变量,用env
就可以了看到所有的环境变量:
环境变量本质就是数据,甚至可以把它当成字符串。
环境变量就是操作系统为了满足不同的应用场景而预先在系统内设置的一大批的全局变量,这些变量在我们整个系统当中,从bash往后一直都会被其他进程访问到。
通过系统调用获取或设置环境变量
如果我们将来想通过指令的方式获取环境变量,我们可以env,打印出系统当中我们自己用户当中所有环境变量信息。
可以echo $PATH
打印指定确定的环境变量内容。
想通过指令的方式去获取可以getenv
接下来我们自己去调一下:
编译运行,
也就是说我们自己写的代码它认识我们了,在root用户下它同样认识。
这件事情的意义在于:USER 环境变量最大的意义,可以标识当前的使用Linux用户,让我们知道当前是以谁的身份在运行Linux。
下面我们再修改代码:判断who如果等于root就执行打印动作,否则就输出“权限不足”。
运行程序:
然后我们切换root用户,并进入我们写的程序文件中,
再次运行程序:
Linux会筛选用户,并告诉用户不能做什么工作,有时候一个文件的属性也能获取,所以系统编写指令的时候,指令的内部做了一大堆的身份认证,身份认证就相当于它可以通过对应的文件属性获取。
所以我们的系统级指令会做权限和身份认证,身份认证有一个重要的环就是通过user来认证。
环境变量在不同的应用场景被使用,我们需要在不同的场景使用不同的环境变量来做某些工作。
环境变量相关命令
- echo: 显示某个环境变量值
- export: 设置一个新的环境变量
- env: 显示所有环境变量
- unset: 清除环境变量
- set: 显示本地定义的shell变量和环境变量
我们可以自己设置一些环境变量:
下面试着理解环境变量的全局性和本地变量:
我们先获取自定义环境变量,
然后编译运行,
因为我们刚定义的不是环境变量,所以myval时not found。
export: 设置一个新的环境变量
export它可以对环境变量作定义,并且如果一个本地变量已经存在,想把它倒成环境变量只需要:
export myval
当我们在命令行运行./mycmd
的时候,bash就是一个系统进程,mycmd也会变成一个进程(fork),mycmd是我们自己写的代码,它是bash的子进程。
环境变量具有全局属性根本原因是:会被子进程全部继承下去。
继承下去的原因是:为了不同的应用场景,让bash帮我们找指令路径,身份认证。有些子进程会用到 这些信息来作为自己代码逻辑的一部分,好比我们前面获取通过获取user环境变量来对我们用户作身份认证,未来可能我们通过获取其他环境变量来确认当前对应用户的信息。
环境变量是属于系统变量中的全局变量,具有全局性,本地变量就只会在当前进程(bash)内有效
set: 显示本地定义的shell变量和环境变量
我们定义一个变量 yourval=4321
,
set命令打印出来的东西很多,有环境变量、PS…
unset: 清除环境变量
通过代码如何获取环境变量
我们了解到,环境变量被子进程继承下去,但是是怎么继承的呢?如何做的?
输入下面代码:我们知道main函数是系统调用的。
运行后我们发现指针数组的0下标指向./mycmd
,
我们继续:
我们发现当我们在命令的内容不断变多时,数组的内容会自动变多
其实所谓的命令行参数本质是依次要把程序名和选项传递给argv。
我们输的命令行操作是一个大的字符串,我们在进行命令行解析的时候,如下:
把在命令行输入的字符以空格为单位拆成一个一个的子字符串,
argc代表的是命令行中一共有多少个子字符串,argv是一张表,是一张映射表,它是一个指针数组,会指向一个一个的字串。
这个东西对我们的意义是什么:
假如我们想做一个./mycmd -a -b -c
这样的一个程序,我们想让-a
-b
-c
分别有不同的操作,同样的可执行程序,我们想让带不同的选项做不同的动作:
编译运行他就告诉我们如何用,
我们就选择一个:
./mycmd -a
剩下的都是一样的,此时我们就可以通过不同的命令行参数,用不同的选项,让同样的程序,来使用这个程序内部不同的功能,这就是命令行参数最大的意义。
下面我们继续:
上面这两张表被我们进程拿到,进程就可以使用这里的环境变量了,所以环境变量是可以被其他进程拿到的。具体证明是NULL结尾如下:
补充完代码后编译运行:此时我们就拿到了系统传的环境变量。
我们自己导一个环境变量export myval=4444
,再次运行就能看到,我们自己导进去的环境变量。
这个环境变量是导给shell的,我们运行程序的时候需要创建子进程,并且还要把shell的环境变量交给子进程。(通过命令行参数)