【从浅学到熟知Linux】环境变量详谈(含使用程序获取环境变量的3种方法、如何查看环境变量)

🏠关于专栏:Linux的浅学到熟知专栏用于记录Linux系统编程、网络编程及数据库等内容。

🎯每天努力一点点,技术变化看得见

文章目录


环境变量基本概念

环境变量一般是指在操作系统中用来指定操作系统运行环境 的一些参数。

环境变量通常具有某些特殊用途,在系统当中通常具有全局特性

【示例1】我们在系统中执行ls命令时,不需要./ls。而我们执行自己编写的C语言程序,并将它编译成test时,我们要执行它就需要./test才能够运行,这是为什么呢?

which命令后带上某个命令,就可以查看该指令的存储位置。如果执行which ls,可以看到ls存储在/usr/bin/目录中。

系统中维护了一个PATH环境变量,系统可以帮助我们在PATH环境变量保存的各个路径中查找命令。我们可以使用echo $[环境变量名]来查看某个环境变量的值,此时我们执行echo $PATH,结果如下图所示。可以发现,PATH环境变量种保存着/usr/bin目录。

也就是说,只要我们执行某个命令,系统默认从PATH环境变量下的各个目录进行搜索,如果存在该命令的可执行文件,则执行,否则就会报错。

而我们自己写的程序并没有保存PATH环境变量指定的目录下时,无法不带./就执行(或者是使用绝对路径的方式)。我们可以通过将该程序移动到PATH环境变量保存的某个目录中,这样就可以不带./运行了。但这种方式会污染系统命令,因为我们的程序并没有经过大量测试,可能存在大量错误,不建议将自己写的命令放入PATH变量的各个目录中。

【示例2】我们在编写C/C++代码的时候,在链接的时候,从来不知道我们的所链接的动态静态库在哪里,但是照样可以链接成功,生成可执行程序,原因就是有相关环境变量帮助编译器进行查找。

查看环境变量的方法

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

下面我们来看一下常见的环境变量:

●PATH:指定命令的搜索路径

命令本质就是可执行文件,我们没有指定命令的可执行文件地址,但它会从PATH环境变量内的各个目录中查找该命令是否存在,存在则执行,不存在则报错。

●HOME:指定用户的主工作目录(即用户登陆到Linux系统中的默认目录)

当我以root用户身份登录时,我的HOME环境变量保存的是/root;但如果我以xiaoming用户身份登录时,我的HOME环境变量保存的/home/xiaoming。从这里可以发现,不同用户的HOME目录(也成为家目录)是不一样的。

●SHELL:当前Shell,它的值通常是/bin/bash

我们启动一个Linux命令行,本质就是执行一个bash程序。bash在执行用户程序、指令时,会fork子进程执行,即使子进程因程序问题而出错,也不会影响到bash的稳定运行,也就不会影响到用户的命令行使用了。

环境变量相关命令

  • echo:显示某个环境变量值(上面已经有介绍,这里不再赘述)

使用实例↓↓↓

bash 复制代码
echo $PWD
  • env:显示所有环境变量

使用实例↓↓↓

bash 复制代码
env
  • export:设置一个新的环境变量

使用实例↓↓↓

bash 复制代码
export jammingpro=666


要注意的是,export设置的环境变量仅在当前会话有效,当我们将整个会话关闭,重新打开Linux命令行时,这个环境变量就会消失。

在系统中,每次启动bash时,该bash都会从系统的环境变量配置文件中读取环境变量信息,export仅仅修改了本次启动的bash的环境变量,一旦关闭重启后,原来设置的环境变量不再存在,新启动的bash会重新从系统的环境变量配置文件中读取环境变量信息

如果我们想设置持久化的环境变量,可以修改/etc/profile添加环境变量,例如:下图中新增了jammingpro=666的环境变量↓↓↓(这样设置后,以后启动Linux的任何bash命令行中都会存在该环境变量)

  • set:显示本地定义的shell变量和环境变量

使用实例↓↓↓

bash 复制代码
set

我们可以在bash命令行直接定义变量,例如:baymaxPro=999(不需要使用export)。而set显示的除了环境变量外,还显示了本地自定义的shell变量。

那本地定义的变量和当前bash的环境变量有什么区别呢?当我们创建子进程时,当前bash的环境变量会被子进程继承,也就是说,bash执行的程序都有和bash相同的环境变量;但本地定义的变量不会被子进程继承。

  • unset:清除环境变量
bash 复制代码
unset [待清除的环境变量名]

由上图可以发现,unset既可以清除环境变量,也可以清除本地自定义的Shell变量。

环境变量组织方式及获取环境变量的3种方法

每个进程都有一张环境表,环境表是一个字符指针数组,每个指针指向一个以'\0'结尾的环境字符串

下面我们介绍3种可以从环境变量表获取环境变量的方法↓↓↓

  • getenv

使用getenv实现pwd命令↓↓↓

c 复制代码
#include <stdio.h>
#include <stdlib.h>

int main()
{
	printf("%s\n", getenv("PWD"));
	return 0;
}
  • environ(第三方变量)

使用environ时,需要先对该变量进行声明,即extern char** environ。下面使用代码打印环境表种的所有内容↓↓↓

c 复制代码
#include <stdio.h>

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

★ps:libc种定义的全局变量environ指向环境变量表,environ没有包含在任何头文件种,所以使用时要使用extern声明。

  • main的env参数(命令行第三个参数)

我们在使用命令执行某些可执行程序时,bash会帮助给该程序传入3个参数↓↓↓

以ls命令为例,ls -a -l,它的命令行参数有3个,分别时ls、-a、-l,因此argv保存的就是{"ls", "-a", "-l", NULL},而第三个参数就是bash传递给它的子进程的环境变量。

下面我们使用main的env参数打印所有环境变量↓↓↓

c 复制代码
#include <stdio.h>

int main(int argc, char* argv[], char* env[])
{
	for(int i = 0; env[i]; i++)
	{
		printf("[%d]->%s\n", i, env[i]);
	}
	return 0;
}

下面我们自定义一个命令xm,该命令只允许用户带一个选项,如果带的选项是-a就输出"xiaoming say => you are nice!!",带-b选项就输出"what are you doing now?",用户选项输出与要求不符的提示用户如何使用该命令↓↓↓

c 复制代码
#include <stdio.h>
#include <string.h>

void Usage()
{
	printf("\r\tYou are supposed to use -a or -b\n");
}

int main(int argc, char* argv[], char* env[])
{
	if(argc == 2 && strcmp("-a", argv[1]) == 0)
	{
		printf("xiaoming say => you are nice!!\n");
	}
	else if(argc == 2 && strcmp("-b", argv[1]) == 0)
	{
		printf("what are you doing now?\n");
	}
	else 
	{
		Usage();
	}
	return 0;
}

验证环境变量的全局属性

环境变量具有全局属性,可以被子进程继承下去。子进程的环境变量是从父进程继承来的,默认所有的环境变量都会被子进程继承。

编写一个程序proc,用于获取名为jammingpro的环境变量↓↓↓

c 复制代码
#include <stdio.h>
#include <stdlib,h>

int main()
{
	printf("%s\n", getenv("jammingpro"));
	return 0;
}

当前bash中开始时没有名为jammingpro的环境变量,此时使用export jammingpro=666设置环境变量,再指向proc程序时,proc程序可以获得该环境变量。说明子进程可以继承父进程的环境变量。

如果我们此时unset名为jammingpro的变量,并定义名为jammingpro的shell自定义变量,此时执行proc程序时会发送段错误。说明子进程不能继承bash中的shell自定义变量。

🎈欢迎进入从浅学到熟知Linux专栏,查看更多文章。

如果上述内容有任何问题,欢迎在下方留言区指正b( ̄▽ ̄)d

相关推荐
乐悠小码3 分钟前
数据结构------队列(Java语言描述)
java·开发语言·数据结构·链表·队列
史努比.5 分钟前
Pod控制器
java·开发语言
敲敲敲-敲代码14 分钟前
游戏设计:推箱子【easyx图形界面/c语言】
c语言·开发语言·游戏
ROC_bird..22 分钟前
STL - vector的使用和模拟实现
开发语言·c++
机器视觉知识推荐、就业指导22 分钟前
C++中的栈(Stack)和堆(Heap)
c++
小han的日常25 分钟前
接口自动化环境搭建
运维·自动化
小扳27 分钟前
Docker 篇-Docker 详细安装、了解和使用 Docker 核心功能(数据卷、自定义镜像 Dockerfile、网络)
运维·spring boot·后端·mysql·spring cloud·docker·容器
MavenTalk28 分钟前
Move开发语言在区块链的开发与应用
开发语言·python·rust·区块链·solidity·move
运维小文31 分钟前
服务器硬件介绍
运维·服务器·计算机网络·缓存·硬件架构
simple_ssn35 分钟前
【C语言刷力扣】1502.判断能否形成等差数列
c语言·算法·leetcode