【Linux】环境变量
- 基本概念
- 命令行参数
- 环境变量
- 认识常见的环境变量
- PATH环境变量
- PWD环境变量
- USER环境变量
- HOME环境变量
- 系统中查看所有的环境变量
- 环境变量的特性
- export导出环境变量
- main函数的第三个参数
- 获取环境变量的方法
- 使用main函数的传参的方式
- 通过getevn函数获取单个环境变量
- 通过第三方变量environ获取
- 本地变量
- 定义本地变量
- 本地变量不具有全局属性
- unset移除环境变量或本地变量
- 加载bash
基本概念
- 环境变量(environment variables)一般是指在操作系统中用来指定操作系统运行环境的一些参数
- 如:我们在编写
C/C++
代码的时候,在链接的时候,从来不知道我们的所链接的动态静态库在哪里,但是照样可以链接成功,生成可执行程序,原因就是有相关环境变量帮助编译器进行查找。 - 环境变量通常具有某些特殊用途,还有在系统当中通常具有全局特性、
在比如在Windows
下我们在查询下载java
或者python
的方法的时候,通常都会有一步骤将我们配置环境变量这一操作,尤其是配置一个将Path
的环境变量,这个Path
通常是填写一串路径。
着Path的作用大概就是:我们下载的软件都是由可执行程序的,而我们一般可能是会在命令行窗口cmd中执行一些命令的,比如我们要执行Git
,而如果我们没有配置环境变量的话,在cmd下是会执行不了的,你需要带上完整的Git
路径才能执行,而如果配置了环境变量则组需要直接执行Git
即可。所以配置环境变量的本质其实就是让系统找到你这可执行程序,配置文件,动静态库之类的。
命令行参数
我们一般在写C/C++时,main可以带参数吗?
如果是在很老的一些教材中,你可能会看到main函数中是带来参数的。
int main(int argc, char* argv[])
{}
而为什么我们之前写main函数的时候没有写呢?主要是之前写代码的场景多不会用到main函数中的参数。
现在我们就来看看这些参数是什么?
int main(int argc, char* argv[])
{int i = 0;for (i = 0; i < argc; i++){printf("argv[%d]: %s\n", i, argv[i]);}return 0;
}
首先我们要知道我们每次输入命令是都会有一个[用户名@主机名:路径]#
的字符串,这个其实就是bash给我们输出的命令行参数,而至于后面的./mytext ……
这个就是bash让我们输入的参数。而既然是让我们输入的,那么bash就肯定会有方法帮我们保存起来,main函数也是函数,当然也是可以进行传参的,所以我们输入的参数都会被bash进行保存起来,可以通过传参的方式进行获取。
而看似我们输入的是以空格输入的一个个字符串,但其实是输入的以空格分割的一个字符串,而bash会根据空格进行切分,最终一一放到了一个指针数组中了。
所以我们argv也叫做是命令行参数表,而我们也说了命令行参数表是以NULL为结尾的,所以我们拿到命令行参数也可以这样子写:
for (int i = 0; argv[i]; i++)
{}
那么为什么要这么干呢?
这样做的原因之一就是我们可以通过不同选项,让我们的一个程序执行内部不同的功能。例如我们要一个程序可以根据我们输入的命令的不同要执行三个不同的功能。
#include <stdio.h>
#include <string.h>
int main(int argc, char* argv[])
{if (argc != 2){printf("Usage:\n\t%s,[1-3]\n",argv[0]);return 1;}if (strcmp(argv[1], "-1") == 0){printf("function 1\n");}if (strcmp(argv[1], "-2")== 0){printf("function 2\n");}if (strcmp(argv[1], "-3") == 0){printf("function 3\n");}return 0;
}
而这里我们可以想到什么,我们之前使用的ls -l,ls -a,ls -n,ls -ald
,所以我们之前所有写的执行,ls就是指令名称,后面的就是执行选项,而我们大部分的指令都是使用c/c++
写的,所以为什么我们的的执行会传递不同的选项,而写会根据传过来的选项执行不同的功能,原因就在与我们最终的选项都会传递个我们main函数当中的argc,argv
,这样就可以根据不同的选项执行不同的功能,所以选项的本质就是命令行参数。
这就是为什么我们之前的使用main函数的时候没有使用到参数,因为我们之前写代码的时候都是使用的图形化界面进行编写的,它已经帮我们做好了一些工作了,而我们的Windows其实也是有很多的选项的比如shoutdown。
环境变量
- 首先环境变量不是一个,而是一堆,他们彼此之间没有关系
- 环境变量,一般是系统内置的具有特殊用途的变量。
我们接触变量总是和语言强相关的,我们在写C/C++代码的时候势必会定义很多的变量,而定义变量的本质就是开辟空间,而在运行期间的程序也是可以开辟空间的。那些现在对于我们的操作系统/bash它能不能在运行期间开辟空间呢?操作系统和bash也是由C/C++编写的,当然是可以。所以系统的环境变量,本质就是操作系统自己开辟空间,并给这块空间起名字和内容。
认识常见的环境变量
PATH环境变量
我们在执行我们的可执行程序的时候我们需要./mytext
或者使用绝对路径运行程序
,而如果我们指向使用我们的可执行程序直接运行的时候,bash就会提示没有找到改命令。这也就是在暗示我们bash没有找到该指令,也就是说bash在指向命令之前是会先进行查找的。但是如果我们使用系统中一开始就有的命令时比如直接执行ls
不需要进行带路径。这是为啥呢?
这只能说明,bash
在执行ls命令之前就已经知道它在哪里,bash
一旦看到ls
命令时就可以直接找到它。而之所以bash能知道是因为有一个PATH
的全局的环境变量。
我们可以使用echo $PATH
查看改环境变量,往后的想要查看某个环境变量只需要使用echo $环境变量名
chuyang@chuyang-virtual-machine:~/Lesson110/110/text_24_9_16$ echo $PATH
/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin:/usr/games:/usr/local/games:/snap/bin
也就所在我们的bash中会有与一块内存空间,里面保存了一一串字符串,并把这个字符串命名为PATH
,然后无论我们在执行任何命令的时候,他都要在PATH
这个路径下进行查找,这个字符串时由多个路径构成使用”:“进行分割。其中每个路径都是系统默认的搜索路径。之所以我们可以直接使用ls进行直接执行,是因为ls在PATH
的路径里,即/usr/bin
所以才能找到它。而我们自己的mytext没有添加到这个PATH
路径里面,所以找不到。
所以PATH存放的都是Linux执行可执行程序的时候的搜索路径,他会在该路径下一个一个的去搜索,一个找不到就去下一个找,知道全部搜索完毕为止,后者找到。
所以如果我们不想像上面那样带路径执行可执行程序的话,我们有两个方法可以:第一我们可以将可执行程序直接拷给到PATH
路径下的任何一个路路径下,这个动作就相当于我们把程序安装到系统中了(这个不建议)。第二直接将可执行程序的路劲添加到PATH
路径下。
这里我们主要使用的第二种方法,将路径添加到PATH环境变量中。
chuyang@chuyang-virtual-machine:~/Lesson110/110/text_24_9_16$ PATH=/home/chuyang/Lesson110/110/text_24_9_16:$PATH
chuyang@chuyang-virtual-machine:~/Lesson110/110/text_24_9_16$ echo $PATH
/home/chuyang/Lesson110/110/text_24_9_16:/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin:/usr/games:/usr/local/games:/snap/bin
注意这里不能直接使用chuyang@chuyang-virtual-machine:~/Lesson110/110/text_24_9_16$ PATH=/home/chuyang/Lesson110/110/text_24_9_16
必须还要加上:$PATH
把老的路径添加上,不然会直接进行覆盖原来的PATH环境变量。
如果我们的不小心没有添加:$PATH
,而是直接进行覆盖了的话,我们的大部分系统命令将会无法执行。
但是这里不用担心,如果我们真的不小心这样做了,只需要进行重启一下即可恢复。具体细节我们后面会讲解。
PWD环境变量
当我们登陆系统的时候,你的系统是怎么知道你的当前所处的路径在哪里呢?我们在执行PWD的时候,系统是怎么知道我们在那个路径下的呢?
那是因为我们有一个PWD的环境变量,这个环境变量会时时刻刻的记录当前用户路径跟新时,这个PWD环境变量也会进行同步更新。
USER环境变量
同样的道理,我们在使用bash
的时候,系统怎么知道我们是谁呢?是因为由USER环境变量。
chuyang@chuyang-virtual-machine:/$ echo $USER
chuyang
HOME环境变量
对应着就是我们登陆bash的时候默认进入我们的家目录。
chuyang@chuyang-virtual-machine:/$ echo $HOME
/home/chuyang
系统中查看所有的环境变量
使用env
命令查看
环境变量的特性
export导出环境变量
我们可以通过export
将我们进行设置添加环境变量。
chuyang@chuyang-virtual-machine:/$ export AGE=18
main函数的第三个参数
int main(int argc, char* argv[], char* env[])
上面使用env我们可以看到所以的环境变量,而前面我们说过了我们使用指令其实就是bash创建的一个个子进程,我们在将进程的使用也说过了,子进程是会继承父进程的数据和代码的,所以这里我们输出一个结论:子进程是可以继承父进程的环境变量。所以main函数的第三个参数就是传递的一个环境变量表,这张表中放着的是从父进程中继承过来的环境变量。
所以说环境变量具有全局属性,环境变量会被子进程包括孙子进程所继承。
#include <stdio.h>
#include <string.h>
int main(int argc, char* argv[], char* env[])
{int i =0;for (i = 0; env[i]; i++){printf("--------env[%d]:%s\n", i, env[i]);}return 0;
}
获取环境变量的方法
使用main函数的传参的方式
我们上面就是通过这种方式进行获取环境变量的。
通过getevn函数获取单个环境变量
直接通过环境变量名获取环境变量。
chuyang@chuyang-virtual-machine:~/Lesson110/110/text_24_9_16$ cat text.cc
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
int main(int argc, char* argv[], char* env[])
{const char* username = getenv("USER");printf("%s\n", username);return 0;
}
chuyang@chuyang-virtual-machine:~/Lesson110/110/text_24_9_16$ ./mytext
chuyang
通过第三方变量environ获取
#include <stdio.h>int main(int argc, char *argv[])
{extern char **environ;int i = 0;for(; environ[i]; i++){printf("%s\n", environ[i]);}return 0;
}
本地变量
定义本地变量
上面我们定义环境变量的方式是使用export
的方式进行导出环境变量。
而这里我们定义本地变量的方式是直接使用变量名:变量内容。
chuyang@chuyang-virtual-machine:~/Lesson110/110/text_24_9_16$ hello=aaaaaaaaaaaaa
chuyang@chuyang-virtual-machine:~/Lesson110/110/text_24_9_16$ echo $hello
aaaaaaaaaaaaa
但是这种本地变量不能使用env
来进行查看,而是要使用set
进行查看.
chuyang@chuyang-virtual-machine:~/Lesson110/110/text_24_9_16$ set | grep hello
hello=aaaaaaaaaaaaa
set
方法几乎会把bash
中的所有变量都显示出来,包括了环境变量和本地变量
本地变量不具有全局属性
上面我们说过了,环境变量是具有全局属性的,可以被子进程包括孙子进程。但是如果是本地变量的话,只能提供给本地使用,即不能被子进程所继承下去。本地变量只在bash内部有效。本地变量不是环境变量。
unset移除环境变量或本地变量
chuyang@chuyang-virtual-machine:~/Lesson110/110/text_24_9_16$ set | grep hello
hello=aaaaaaaaaaaaa
chuyang@chuyang-virtual-machine:~/Lesson110/110/text_24_9_16$ unset hello
chuyang@chuyang-virtual-machine:~/Lesson110/110/text_24_9_16$ echo $hello
//什么都没有
加载bash
上面我们挖了一个坑,就是当我们覆盖PATH环境变量的时候,我们不要慌张,只需要重启bash即可。那么为什么呢?
这就得回到我们一开始启动bash
的时候了,我们一开始启动bash
的时候,这些环境变量从哪里加载过来的啊?其实我们在启动bash
之前的时候bash
中有很多的配置文件,这些配置文件里面记录了操作系统所需要的所以环境变量,而到这里我们其实也可以猜到了,这些环境变量其实是存放在文件中的,也就是存放在磁盘上的,当我们加载bash的时候,是将配置文件中的环境变量拷贝了一份,bash
是不是一个进程啊,既然是进程那要不要加载到内存啊,所以就算我们将PATH
修改了,修改的只是内存级的环境变量,并不影响磁盘上的,所以只要我们对bash
进行重启的话就会恢复成原来的样子。
所以说所有的环境变量都是保存在磁盘上文件中的。其中我们可以在家目录中看到这个文件。存放在家目录中的.profile(Ubuntu版本下的)
中,当我们启动bash的时候,都会从这个文件中变量。
而我们现在可以自己添加一个变量并进行重新启动。
// 在后面添加这条命令
MYVAL=hello
export MYVAL // 注意记得导出变量
chuyang@chuyang-virtual-machine:~$ echo $MYVAL
hello