文章目录
1. 前言
本篇文章将以PATH环境变量为例来对整个Linux环境变量进行学习理解。
本文着重讲解了什么是PATH环境变量、如何添加PATH环境变量、系统中的其他环境变量、环境变量的由来、环境变量的基本操作以及命令行参数中环境变量的体现。
2 什么是PATH环境变量
Linux中的各种指令本质上是/usr/bin/
目录下的一个个可执行程序,和我们自己编写的可执行程序没有任何区别:
但是我们发现,执行我们自己的程序时需要指定路径,但是执行Linux中的各种指令却不需要指定路径:
这是因为系统中存在PATH环境变量,PATH中存放着这些指令的地址。当我们使用这些指令时,系统会自动去PATH中寻找对应指令,如果找到了就执行,找不到就报错command not found
。
3. 如何添加PATH环境变量
我们可以使用echo $PATH
来查看PATH环境变量中包含的内容:
注:PATH中不同路径之间用:
分割。
我们也可以通过向PATH中添加内容来让我们自己的程序可以不需要指定路径就能被执行:
==法一:==直接将程序添加到/usr/bin/
目录下(不建议使用这种方法,因为我们写的程序没有经过测试,容易污染指令池)。
==法二:==使用export
命令将当前可执行程序的路径导入到PATH中。
法二相关说明:
- 其中的
$PATH
代表之前PATH
中内容,:
之后的为新添加的内容。注意不要直接export PATH=/home/czh/practice
,这样会把之前的PATH覆盖掉,使得Linux中的各种指令必须指定路径使用。 - PATH中不能由空格,因为Linux中以空格为分隔符。
- 使用export命令声明,变量只在**当前的shell(BASH)或其子shell(BASH)**下是有效的,在关闭shell后失效,再打开新shell时就没有这个变量,需要使用的话还需要重新定义。
4. 系统中的其他环境变量
PATH环境变量只是系统中众多环境变量的一种,除了PATH,我们还有许多其他环境变量,且不同的环境变量有不同的功能,也适用于不同的场景,比如:
HOSTNAME
:主机名USER
:当前用户名PWD
:当前系统路径HOME
:当前用户的家目录HISTSIZE
:shell能记忆的最多历史命令的条数
我们可以使用env
命令来查看系统中所有的环境变量:
5. 环境变量的由来
ls -al /home/czh
可以发现家目录下存在两个隐藏文件.bash_profile
与.bashrc
:
实际上,当我们在登录shell时,操作系统会让我们当前的shell进程执.bash_profile
中的内容,而.bash_profile
又会调用执行.bashrc
,它们会将对应的环境变量导入到shell
进程的上下文环境中。所以,如果我们上面不小心将$PATH
覆盖掉了也不用担心,重新登录shell就好了。
至此,环境变量的定义如下:
环境变量是操作系统为了满足不同的应用场景,预先在系统内设置的一大批全局变量,这些变量往往具有特殊功能,且能够一直被bash以及bash的子进程访问。
注:环境变量具有全局属性的根本原因是环境变量会被子进程继承。
6. 环境变量的基本操作
6.1 设置环境变量
Linux命令行其实是可以定义变量的,但是以这种方式定义出来的变量是本地变量,即只在bash进程中有效,而不是环境变量,因为环境变量具有全局属性:
我们可以使用export
直接定义环境变量,也可以使用它将已存在的本地变量导为环境变量:
我们可以使用set
命令来查看所有变量,包括环境变量和本地变量;使用 unset 来取消变量,包括环境变量和本地变量:
6.2 通过getenv获取环境变量
我们可以使用echo $环境变量名
来获取特定的环境变量,也可以通过getenv()
函数来获取环境变量:
其中name
是我们要获取的环境变量的名称,如果获取成功就返回该环境变量的具体内容,失败就返回null
。
有了getenv
函数后,我们就可以自己编写系统中的某些指令了,比如pwd
:
#include <stdio.h>
#include <stdlib.h>#define MYPWD "PWD"int main()
{char* env = getenv(MYPWD);printf("%s\n", env);return 0;
}
6.3 环境变量的应用场景
我们上面提到,环境变量是操作系统为了满足不同的应用场景,预先在系统内设置的一大批全局变量。其中PATH是为了满足我们指令路径搜索的需求,而除了指令需求之外还有许多其他需求,其中非常重要的一个就是身份认证。
我们以一个例子说明:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>#define USER "USER"int main()
{char* who = getenv(USER);if(strcmp(who, "root") == 0){printf("Operation success!\n");}else {printf("Permission denied!\n");}return 0;
}
注:这里要使用su -
,而不能使用su
,因为su -
会重新登录shell,此时shell会重新加载环境变量,让$USER
从czh
变为root
,而su
只是把用户身份切换为root
。
我们可以在程序内部通过getenv
函数来获取当前的Linux用户,然后判断其是否具备某种权限,再执行对应操作,另外,我们还可以通过stat
来获取一个文件的其他属性,比如读写执行等,然后根据这些属性判断一个用户是否能对该文件进行操作:
7. 通过命令行参数获取环境变量
我们上面提到,程序可以通过getenv
函数来获取环境变量,其实除了getenv
函数,程序还可以通过命令行参数传递来获取环境变量。
学过C语言的同学应该都知道,main
函数其实是有参数的,且这些参数通过命令行传递:
int main(int argc, char* argv[], char* env[]);
其中argv
是一个指针数组,数组里面的每一个元素都指向一个字符串,argc
用来指定数组元素的个数;它们配合使用可以实现类似于ls -a -l -d
选项的功能。
而指针数组env
就是用于接受父进程传递过来环境变量的参数,我们可以通过在main
函数中打印env
中的内容来验证它:
#include <stdio.h>
#include <stdlib.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;
}
程序也可以通过环境表environ
来获取环境变量
环境表是一个字符指针数组,每个指针指向一个以’\0’
结尾的环境字符串,每个进程都会收到一张环境表:
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>int main(int argc, char* argv[], char* env[])
{extern char** environ;int i = 0;for(i=0; environ[i]; i++){printf("%d:%s\n", i, environ[i]);}return 0;
}
注:environ是一个全局的外部变量,所以切记使用前要用extern关键字进行声明,然后再使用。