Linux:环境变量

1.前言

在Windows系统中,当我们安装python环境或者是java环境的时候,可能需要配置环境变量这一个东西,环境变量分为两个,一个是用户的环境变量,另一个是系统的环境变量。我们安装软件的时候要求我们配置环境变量的目的是为了让系统能够找到可执行程序、配置文件、动静态库。在Linux中也有环境变量,同样也分为用户的环境变量和系统的环境变量,环境变量这种东西对于大家而言是比较陌生的,下面就先来讲解和和环境变量相近的概念,再来讲解环境变量是什么。


2.main函数参数

我们在学习C语言或者是C++语言的时候,main函数一般都是这样去写的,例如:

cpp 复制代码
int main()
{

    return 0;
}

main函数其实是可以带参数的,它的参数是这样的,例如:

cpp 复制代码
int main(int argc,char* argv[])
{

    return 0;
}

main函数的第二个参数argv是一个指针数组,它里面放的全部是char*,char*在C语言无非就指向字符串,指向字符的地址,所以main函数的第二个参数argv指针数组里的元素指向了一个个的字符串,这些字符串我们没有见过的原因是我们没有用过,也没有对应的场景去使用。第一参数argc表示的是argv这个指针数组的元素个数,接下来就将argv里面的元素指向的字符串打印出来看看,例如:

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

使用gcc编译生成一个名为test.out的可执行程序后,来运行看一下结果是什么,例如:

在运行test.out时多加上一些选项,例如:

经过上面实验可以看出,在运行test.out时会将命令行里面的参数使用空格分隔成一个个字符串。

下面就为大家解释一下:

我们在命令行上做输入时,前面的用户名、主机名、工作目录,这些是命令行解释器bash给我们输出的字符串,如下图所示:

后面的内容是我们的输入字符串,例如我们输入的"./test -a -b -c",如下图所示:

当我们输入这个字符串后,被bash读取到了,就会将这个字符串以空格做分割,转化成一个个的子串以NULL结尾,并且保存起来,在执行test.out时,将这些子串和子串的个数传递到main函数当中,main函数就拿到了我们输入的参数了,所以打印出来的就和我们输入结果一样,只不过被分割成了子串。传递到main函数的这些子串可以被称为一张表,这种表被称为命令行参数表
在Linux中我们学到指令大部分都是可执行程序,例如ls指令,我们在使用ls指令加上不同的选项,执行出来的结果不同,所以,我们可以通过main函数的参数来实现一个通过不同的选项,执行结果不同的程序,例如:

cpp 复制代码
#include <stdio.h>
#include <string.h>
int main(int argc,char* argv[])
{
    if(argc != 2)
    {
        printf("使用错误,需要加上选项\n");
        return -1;
    }

    if(strcmp(argv[1],"-a") == 0)
    {
        printf("执行-a选项的功能\n");
    }
    else if(strcmp(argv[1],"-b") == 0)
    {
        printf("执行-b选项的功能\n");
    }
    else if(strcmp(argv[1],"-c") == 0)
    {
        printf("执行-c选项的功能\n");
    }
    else
    {
        printf("没有该选项\n");
    }

    return 0;
}

大部分的指令都是用C/C++写的,指令能够传递选项,能够根据选项来执行不同的功能的原因就是因为我们所输入的字符串会被分割成一个个的子串,并且传递到main函数参数当中。**选项的本质就是命令行参数,**命令行参数是Linux指令选项的基础。
我们在学习C/C++语言时,写代码不用命令行参数的原因是因为我们在图形化界面所写的,例如VS上。


3.什么是环境变量

环境变量其实和命令行参数是比较像的。环境变量不是一个,而是多个,这些变量彼此之间是没有关系的,例如:有的环境变量是记录当前的用户名,有的是记录当前所处的工作目录,有的是记录主机名,有的是可执行程序的搜索路径。环境变量是操作系统内置的且具有特殊用途的变量。
我们对于变量的理解可能是在计算机语言上,例如在C/C++语言上定义变量,定义变量的本质其实就是开辟空间,为了方便表示这段空间所以才给了这段空间取了个名字,这段空间可写可读。

操作系统和bash是用C语言写的,它们能够在运行中开辟空间,所以所谓的系统的环境变量其实是系统自己开辟空间,然后给这段空间名字和内容。


4.认识环境变量

1.PATH

在Linux中,我们要运行自己所写的程序,需要到该程序的目录下以./开头再输入程序的名字才可以运行该程序,也可以用绝对路径+程序名才能运行该程序,指令的本质也是可执行程序,我们想执行指令的时候只需要输入指令名就能运行,为什么我们所写的程序不能像指令一样直接输入名字就能运行?原因是因为在系统当中存在一个全局的环境变量,这个环境变量的名字叫:PATH,要查看环境变量的内容所需要的指令:

bash 复制代码
echo $环境变量名

例如查看PATH的内容:

bash 复制代码
echo $PATH

执行结果:

也就说PATH这个环境变量里面的内容是"/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin:/usr/games:/usr/local/games:/snap/bin"

这是一串字符串,也是一个路径,以:号分割由多个子路径组成,如下图所示:

这些子路径都是系统默认的搜索路径,要执行一个程序,前提是要找到该程序,我们所用的指令是在/usr/bin路径下,所以能被找到,我们自己所写的程序所在的路径没有被添加到PATH这个环境变量里,操作所以我们需要进入程序的目录加上./或者是使用绝对路径来执行程序。如果想让我们写的程序使用起来和指令一样不用带路径,我们可以将我们所写的程序复制到PATH这个环境变量中任意一个路径下,这种方式就是安装。除了复制外,我们还可以将我们的所写的程序路径添加到PATH里面去,操作方式:

bash 复制代码
PATH=程序所在路径:$PATH

修改PATH时如果不加上$PATH(老的PATH环境变量),就会将原来的内容覆盖掉,系统就会找不到指令所在路径,我们也就无法使用指令除非带上路径,重新打开xshell即可解决
2.PWD

PWD这个环境变量里面的内容记录的是用户所在的路径,当用户所在的路径改变时,PWD该环境变量也会同步被更新,查看PWD环境变量的方式:

bash 复制代码
echo $PWD

我们所使用的指令pwd的本质是读取PWD该环境变量。
3.USER

USER这个环境变量里面的内容记录的是当前的用户名,查看USER环境变量的方式:

bash 复制代码
echo $USER

我们所使用的指令whoami的本质是读取USER该环境变量。
4.HOME

HOME该环境变量记录的是当前用户的家目录。
要查看系统中所有的环境变量所使用的指令是:

bash 复制代码
env

当我们启动操作系统时,系统会将用户所需要维护起来数据保存起来,这些被保存起来的数据就是环境变量,当操作系统需要识别用户名时、当前工作路径时、当前主机名时等等,可以通过环境变量去找。


5.环境变量的特性

上面说过,查看单个环境变量的方式是:echo $环境变量名,要查看全部的环境变量所使用的指令是env,所有的环境变量都是key=value,如下图所示:

如果我们要自己定义一个环境所使用的方法是:export Key=value,例如定义一个AGE的环境变量,它的内容为20,定义方法:

bash 复制代码
export AGE=20

定义好之后,使用env或者是echo就可以查看到,如下图所示:

环境变量的本质:

main函数其实有3个参数,除了argc和argv外还有一个参数叫env,如下所示:

cpp 复制代码
int main(int argc,char* argv[],char* env[])
{
    return 0;
}

env和agrv几乎一模一样,都是指针数组,数组以NULL结尾,里面的元素指向都是一个个的字符串,这一个个的字符串都是环境变量,可以将这些环境变量打印出来,例如:

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

打印出来的结果和使用指令env显示出来的结果一模一样,就连我们使用export所定义的环境变量也在,所以bash会把环境变量传递给main函数参数env。

当我们在执行我们的程序时,bash会将命令行参数和命令行参数的个数交给main函数,我们所运行起来的程序是父进程bash所创建的子进程,bash会将环境变量的起始地址以参数的形式传递给我们所运行的程序里的main函数,所以我们的程序就拿到了父进程bash给的环境变量。环境变量是可以被子进程继承下去的,环境变量具有全局属性的原因是因为环境变量会被所有的子进程继承下去(从bash开始,不断启动新的进程/创建新的子进程,像一棵树一样开枝散叶),环境变量大部分是共享的,某一个进程如果要修改就会发生写时拷贝。


6.环境变量的获取

环境变量不仅可以通过传参的方式获得,C的库提供了一个char**类型的变量,该变量和main函数的参数env一样能够获取到环境变量,该变量是:

cpp 复制代码
#include <unistd.h>

extern char** environ;

使用该变量打印出来后结果和使用指令env的输出结果一样,如下所示:

cpp 复制代码
#include <stdio.h>
#include <unistd.h>

extern char** environ;
int main()
{
	for (int i = 0; environ[i]; i++)
	{
		printf("%s\n", environ[i]);
	}
	return 0;
}

环境变量还可以通过系统调用获得,该函数是:

cpp 复制代码
#include <stdlib.h>

char *getenv(const char*name);

getenv该函数的功能是根据环境变量的名字获取环境变量的内容。使用该函数的好处就是可以根据环境变量名来获取环境变量,使用main函数参数或者是environ变量来获取环境变量还需要解析字符串,这样做不方便。

7.本地变量

除了环境变量这个概念外,还有一个概念叫做本地变量,我们可以直接在命令行上定义本地变量,定义方式:Key=value,例如:

定义好之后可以通过查看环境变量的方式来查看本地变量,例如:

使用env指令无法看到本地变量,需要使用指令set才能查看到,set指令的作用是将bash当中所有的变量显示出来,包括环境变量和本地变量。
本地变量只在bash有效,不能被子进程继承下去。本地变量存在的意义是让shell成为一门语言,shell是一个脚本语言。
当我们定义好本地变量后,如果想要删除所使用的方式是:

bash 复制代码
unset 本地变量名/环境变量名

unset不仅可以删除我们定义的本地变量,还可以删除环境变量。

相关推荐
..过云雨几秒前
04.【Linux系统编程】基础开发工具2(makefile、进度条程序实现、版本控制器Git、调试器gdb/cgdb的使用)
linux·笔记·学习
zzzsde11 分钟前
【Linux】初识Linux
linux·运维·服务器
渡我白衣20 分钟前
Linux网络:应用层协议http
linux·网络·http
pofenx33 分钟前
使用nps创建隧道,进行内网穿透
linux·网络·内网穿透·nps
Ronin30533 分钟前
【Linux系统】单例式线程池
linux·服务器·单例模式·线程池·线程安全·死锁
desssq1 小时前
ubuntu 18.04 泰山派编译报错
linux·运维·ubuntu
Lzc7741 小时前
Linux的多线程
linux·linux的多线程
清风笑烟语1 小时前
Ubuntu 24.04 搭建k8s 1.33.4
linux·ubuntu·kubernetes
Dovis(誓平步青云)2 小时前
《Linux 基础指令实战:新手入门的命令行操作核心教程(第一篇)》
linux·运维·服务器
好名字更能让你们记住我2 小时前
MYSQL数据库初阶 之 MYSQL用户管理
linux·数据库·sql·mysql·adb·数据库开发·数据库架构