【Linux】环境变量

CSDN 2024-06-11 09:07:04 阅读 90

一、概念

环境变量(environment variables)一般是指在操作系统中用来指定操作系统运行环境的一些参数,是系统提供的一组name/value形式的变量,相当于给系统或用户应用程序设置的一些参数

每个环境变量都分别有自己不同的用途。我们先来认识其中一个环境变量:PATH,并通过这个变量来简单了解一下环境变量的作用。


二、环境变量PATH

在Linux中,我们直接输入命令就可以执行,但是如果要运行一个程序,则需要带上路径

例如我们运行当前路径下的程序时,就需要加上相对路径才能运行 

如果不加路径,就会报错,提示"command not found"

这说明命令在执行的时候是需要被查找的,在哪里查找呢?实际上就是在环境变量PATH的路径下查找。

我们可以通过echo $PATH查看PATH环境变量的内容:

可以看到PATH实际上就是许多个路径,当我们运行命令时,系统就会在这些路径下查找是否有对应的命令,如果有则执行。

进行猜想:如果我们将一个路径添加到PATH环境变量中,是否能够像运行命令一样来运行该路径下的程序呢?

首先我们将PATH的内容修改一下:

当我们修改PATH时,会将原来的值覆盖,如果我们想实现在原来的值后面添加一个路径,则需要在路径前面加上$PATH

现在再查看一下PATH环境变量的内容,可以看到我们的路径已经添加进去了:

接下来,我们通过export PATH命令将修改后的PATH重新加入环境变量中,然后我们就可以通过命令的方式来运行我们的二进制程序了:

需要知道的是,修改PATH环境变量只在当前用户下有效,并且当重启终端后就会复原,因为这种对环境变量的修改是临时性的。


三、Linux中的环境变量

Linux中常见的环境变量有: 

PATH:指定系统查找可执行文件的路径HOME:指定用户的主工作目录SHELL:指定当前用户默认使用的ShellUSER:当前用户名LANG:系统的默认语言......

如果我们想查看所有的环境变量,可以使用env命令


四、环境变量相关操作

4.1 unset

除了前面提到的echo、export和env,如果我们想取消一个环境变量可以用unset命令

例如我们随便添加一个环境变量:

要想删除这个环境变量,通过unset + 变量名就可以删除了

4.2 getenv

getenv是一个C库函数,以下是它的声明

char *getenv(const char *name)

这个函数可以传入一个环境变量名,返回该变量名的值,例如我们运行以下代码:

#include <stdio.h>#include <string.h>#include <stdlib.h>int main(){ char name[40]; strcpy(name, getenv("USER")); if(strcmp(name, "root") == 0) { printf("root用户\n"); } else { printf("普通用户\n"); } return 0;}

可以看到我们向getenv函数中传入了环境变量USER,所以它会返回当前用户名。

运行代码,结果如下:

4.3 main函数传参

(1)命令行参数

main函数也是函数,只要是函数就会被调用,也可以传入参数,所以我们的main函数实际上也是可以带参的:

int main(int argc, char *argv[]){}

这两个参数就是main函数的命令行参数。 

但是main函数中的这两个参数是什么意思呢?

首先可以观察到,argv是一个指针数组,存放的是char*类型的指针,所以可以知道这个数组用于存放字符串。

而另一个参数argc,实际上就是数组argv中存放的元素数量。

现在,我们来观察一下argv中到底存放了什么东西,运行下面的这段代码

#include <stdio.h>int main(int argc, char *argv[]){ int i = 0; for(;i < argc;i++) { printf("argv[%d]: %s\n", i, argv[i]); } return 0;}

结果如下:

可以看到此时argv数组中存放了我们输入的命令字符串

我们知道,在输入命令的时候是可以带一些选项的,如果我们在运行自己的二进制程序时也带一些选项的话,结果就会变成这样:

通过观察我们就能发现,在输入命令时,如果我们的命令中带有选项,那么就会被打散成多个字符串,而argv数组中存放的就是这些字符串的地址,并且最后一个位置是NULL。

因为我们在Windows下不用通过命令来运行代码,所以平时我们基本用不到命令行参数。但是在Linux下这两个参数就有它们的用途了,例如:

#include <stdio.h>#include <string.h>int main(int argc, char *argv[]){ if(argc != 2) { printf("%s -[a|b|c|d]\n", argv[0]); return 0; } else if(strcmp(argv[1], "-a") == 0) { printf("function 1\n"); } else if(strcmp(argv[1], "-b") == 0) { printf("function 2\n"); } else if(strcmp(argv[1], "-c") == 0) { printf("function 3\n"); } else if(strcmp(argv[1], "-d") == 0) { printf("function 4\n"); } return 0;}

运行代码,结果如下:

可以看到,当我们输入不同的选项时,就可以执行不同的功能了,这就是命令行参数的用途。

命令行参数可以为指令、工具、软件等提供命令行选项的支持

 命令行参数不只是C/C++需要支持,几乎所有的语言都需要支持命令行参数,因为用这些语言写出来的软件都需要根据选项来定制化不同的功能。

(2)环境变量表

实际上,main函数中不止能传两个参数,还有第三个参数——环境变量表

int main(int argc, char *argv[], char *env[]){}

env和argv一样,都是一个存放char*类型的指针数组,而通过它的名字我们就可以知道其中存放的就是环境变量。通过下面这段代码进行验证:

#include <stdio.h>#include <string.h>int main(int argc, char *argv[], char *env[]){ int i = 0; for(; env[i]; i++) { printf("env[%d]: %s\n", i, env[i]); } return 0;}

结果如下:

可以看到,env中的环境变量和我们输入env命令打印出来的环境变量是一样的。

当我们运行二进制程序时,这个进程就是bash的子进程。那么是否可以认为子进程可以继承父进程的环境变量呢?

实际上我们运行的进程,都是bash的子进程,而bash在启动的时候会从操作系统的配置文件中读取环境变量信息。在创建子进程的时候,也会通过传参等方式将环境变量继承给子进程

环境变量通常具有全局属性,可以被子进程继承下去。除了环境变量,还有不具有全局属性的本地变量,例如:

这种变量是无法被子进程继承的,也不会存在于环境变量表中。在命令行中直接定义的变量就叫做本地变量

如果我们想把本地变量存到环境变量表中,用export命令就可以了

前面说过,子进程会继承父进程的环境变量信息,那么我们再运行一次程序试试:

可以看到,当前我们的程序就已经拿到了新增的VAL环境变量了

现在我们用unset命令把这个环境变量删除,并重新将其设置为一个本地变量。

4.4 常规命令与内建命令

前面提到过,子进程无法继承父进程的本地变量,只能继承环境变量

而我们在Linux中输入的命令实际上也是bash的子进程,所以理应也无法读取到bash的本地变量

但是为什么我们用echo命令还能打印出bash的本地变量呢?

其实并不是所有的命令都要创建子进程,Linux中分为两种命令:

常规命令:通过创建子进程完成内建命令:不创建子进程,而是由bash亲自执行

例如cd命令如果通过创建子进程来完成,由于进程的独立性,它只会修改子进程的工作路径。但是实际上是父进程的路径发生更改,因此cd其实也是一个内建命令。

4.5 第三方变量environ

我们不一定要通过传参的方式来获取环境变量表,还可以通过environ——一个指向父进程的环境变量表的指针,来获取环境变量

#include <stdio.h>#include <unistd.h>int main(){ extern char** environ; int i = 0; for(; environ[i]; i++) { printf("%d : %s\n", i, environ[i]); } return 0;}

environ是在libc中定义的全局变量,没有包含在任何头文件中,所以在使用时需要用extern声明

运行代码,结果如下:

如有错误或遗漏欢迎在评论区指出

完.



声明

本文内容仅代表作者观点,或转载于其他网站,本站不以此文作为商业用途
如有涉及侵权,请联系本站进行删除
转载本站原创文章,请注明来源及作者。