进程之环境变量

张开发
2026/5/5 12:36:06 15 分钟阅读
进程之环境变量
本篇目标:理解环境变量熟悉常见环境变量及相关指令一.环境变量1.概念引子我们可能会有这样的疑问我们在编写C/C代码的时候在链接的时候从来不知道我们的所链接的动态静态库在哪里但是照样可以链接成功生成可执行程序原因就是有相关环境变量帮助编译器进行查找当然今天讲的并不是动静态库以后会讲的那什么是环境变量呢环境变量(environmentvariables)⼀般是指在操作系统中用来指定操作系统运行环境的⼀些参数但是光是这样说肯定是不明不白地下面就由浅入深的讲解它。2.命令行参数先别急着了解环境变量可以先了解一下命令行参数。2.1.概念命令行参数就是你在启动程序时直接在程序名称后面输入的附加信息例如我们常用的ls -l中的-l就是命令行参数而ls 就是命令本身下面用一个我们可能没见过的c语言代码演示一下#include stdio.h int main(int argc, char* argv[]) { //... return 0; }main函数其实也是有参数的而参数中的argc其实就是个计数器用来记录程序的命令行参数总数它永远至少是1因为即使没输入任何参数程序本身的名字也会占用一个位置。argv是一个指向变长字符串数组的指针每个字符串代表一个命令行参数在程序启动时操作系统会将命令行字符串拆分存储在进程的用户栈空间内并由argv指向这些地址如果没有命令行字符串那么argv[0]就默认是程序本身的名字代码演示code.c中#include stdio.h int main(int argc, char* argv[]) { for (int i 0; i argc; i) { printf(%s , argv[i]); } printf(\n); return 0; }makefile中code:code.c gcc -o $ $^ -stdc99 PHONY:clean clean: rm -rf code输出结果可以看出当我们输入额外的-a/-b/-c时额外的-a/-b/-c都会被填进到argv所指向的变长字符串数组中所以假设我们输入./code -a -b -c时就会创建这个表如图那么是谁在做这件事呢答案就是bashBash 将我们输入的每一个字符以空格分隔来依次存入了这张表中下面用代码来加深我们的理解#include stdio.h #include string.h int main(int argc, char *argv[]) { if(argc!2) { printf(参数不匹配\n); } for (int i 1; i argc; i) { if (strcmp(argv[i], -a) 0) { printf([匹配成功] 索引 argv[%d]: 检测到 -a执行 A 逻辑。\n, i); } else if (strcmp(argv[i], -b) 0) { printf([匹配成功] 索引 argv[%d]: 检测到 -b执行 B 逻辑。\n, i); } else if (strcmp(argv[i], -c) 0) { printf([匹配成功] 索引 argv[%d]: 检测到 -c执行 C 逻辑。\n, i); } else { printf([未知参数] 索引 argv[%d]: %s程序跳过。\n, i, argv[i]); } } return 0; }输出结果可以看出我们通过在./code后面加上-a/-b/-c就可以实现打印特定的内容这是不是与我们的命令后面的命令命令行参数(选项)十分十分的类似所以我们可以得出下面的结论bash会为每个进程创建一张argv表用来支持实现选项功能可是这又有另外一个问题我们执行./code时是在当前目录下执行这个程序但是ls -al在当前目录下并没有啊他又是如何执行的呢3.环境变量我们在界面按下env即可查看所有的环境变量如图下面讲解一下PATH3.1.PATH环境变量操作echo $PATH即可打印当前的搜索路径列表如图作用提供一套自动搜索可执行文件的目录清单。例如我们在终端输入一个不带路径的命令如 ls 时系统会按照 PATH 中列出的目录顺序从左到右依次查找是否存在同名的可执行文件。所以我的意思就是如果将我们可执行程序添加到这个表里面。那么当我们想要运行code时就不需要./code了可以直接code下面我来演示一下虽然将/home/kong/code_git/fufu直接粗暴的添加到了PATH里面但是也导致了对PATH的覆盖不过也不用担心我们直接退出重新连接即可恢复。此时我就可以在这里输出一个结论当我们进入程序时bash会为我们创建一个环境变量表bash会将env所呈现的所有的环境变量添加到这个表里面。但是这也引出了另外一个问题环境变量最开始从哪里来的呢这就不得不提到系统的相关的配置文件了。3.2.配置文件其实我们在/root下还有许多的隐藏目录/文件如图今天主要讲.bashrc与.bash_profile先打开这两个文件如图.bash_profile文件./bashrc文件在打开/etc/bashrc文件注意if里面的.就是告诉 Bash不要只运行那个文件要把那个文件里的所有变量定义都搬到我当前的内存里来额/etc/bashrc中也存在环境变量。结论.bash_profile向./bashrc中拿环境变量./bashrc向/etc/bashrc中拿环境变量。所以如果我们将我们想要运行的程序放到这个配置文件时当我们重连接时就可以直接运行了。4.认识更多的环境变量1.HOSTNAME代表的时是你当前连接的 Linux 服务器的主机名2.HISTSIZE代表的是当前程序最多能保存的执行过的命令我们也可以通过history来查看我们的历史命令。3.USER和LOGNAME都是 Linux 系统中标识用户的环境变量绝大多数直接登录的场景下两者值相同。4.PWD是表示 Linux 系统中当前工作目录环境变量5.HOME表示的是Linux 系统中当前用户的主目录家目录环境变量例如我们在root权限下HOME/root在kong普通用户下HOME/home/kong所以当我们操作cd ~时~就会被替换为HOME。5.获取环境变量5.1.命令1.env: 显示所有环境变量2.echo:显⽰某个环境变量值3.export: 设置⼀个新的环境变量例如export PATH$PATH:可执行文件所在的绝对路径即可添加新的环境变量4.unset: 清除环境变量5.set: 显示本地定义的shell变量和环境变量5.2.代码5.2.1.命令行第三个参数env#include stdio.h int main(int argv,char*argc[], char *env[]) { for( int i 0;; env[i]; i) { printf(env[i]-%s\n,i, env[i]); } return 0; }输出结果如果我们通过export来创建环境变量例如export MYENV111111export MYENV222222export MYENV333333在env就如图所示可以看出我们自己创建的环境变量导入到了bash里面此时在运行code就会如图所示所以我们可以得出结论父进程的环境变量可以被子进程继承所有的进程都可以拿到环境变量所以这也可以证明环境变量具有全局性。5.2.2.通过第三方变量environ#includestdio.h int main(int argc, char *argv[]) { extern char **environ; int i 0; for(; environ[i]; i) { printf(environ[%d]-%s\n,i, environ[i]); } return 0; }5.3.3.通过getenv获取#include stdio.h #include stdlib.h int main() { printf(%s\n, getenv(PATH)); return 0; }如果我们通过export来创建环境变量例如export MYENV111111export MYENV222222export MYENV333333在env就如图所示可以看出我们自己创建的环境变量导入到了bash里面此时我们就可以创建一个只可以当前用户可以使用的程序例如#include stdio.h #include stdlib.h #include string.h int main(int argc, char *argv[]) { // 1. 从环境变量表中获取当前执行者的用户名 char *current_user getenv(USER); // 2. 核心逻辑比对是否为 kong // 如果环境变量里根本没有 USER或者名字不是 kong if (current_user NULL || strcmp(current_user, kong) ! 0) { printf(权限拒绝该程序仅限用户 [kong] 执行。\n); printf(当前尝试运行的用户是: %s\n, (current_user ? current_user : 未知)); return 1; // 异常退出 } // 3. 验证通过后的逻辑 printf(验证通过欢迎回来kong。\n); printf(正在加载您的私人配置...\n); // 可以在这里添加你只想让自己运行的功能代码 return 0; }

更多文章