当前位置: 首页 > news >正文

谈谈环境变量

为什么我们在终端输入 ls,系统就知道要去哪里找这个命令?为什么我们编译代码时,编译器总能找到那些“藏”在系统各处的库文件?这一切,都要归功于一个低调而强大的存在——环境变量

一、基本概念

  • 环境变量 , 一般是指在操作系统中用来执行操作系统运行环境的一些参数
  • 如 : 我们在C/C++代码的时候,在链接的时候,从来不知道我们所连接的动态静态库在哪里,但是同样可以链接成功,生成可执行程序,原因就是有相关变量帮助编译器进行查找
  • 环境变量通常由某些特殊用途,还有在系统中通常具有全局特性!!!

以前学编程语言的时候,我们说main其实是程序的入口,但是我们在编写的时候,往往会不写两个参数,其实main函数也是由其他函数调用来的。

char* [] : 要么指向字符地址 , 要么指向字符串地址 , 到底是啥呢?

1.1 命令行参数表

我们新建一个code.c文件进行验证,查看一下 argv 这个指针数组 以及argc这个变量到底存储了啥!!!!

我们不难发现,这个命令被分割了,并且填入到argv这个指针数组里,同时argc会记录有多少个字串!!!!!有啥用,为啥要放在这里,谁需要???

1) 先搞懂 argc 和 argv 是啥

当你在终端里输入一个命令(比如 ls -a -b -c)并执行时,系统会把这个命令拆分成一个个 “小片段”,然后交给程序的 main 函数。

  • argc:是 “argument count” 的缩写,意思是参数的数量。比如 ls -a -b -c,这里有 ls-a-b-c 这 4 个部分,所以 argc 的值就是 4。
  • argv:是 “argument vector” 的缩写,它是一个指针数组,里面每个元素都是一个字符串,依次存放着拆分后的命令片段。对于 ls -a -b -cargv[0] 就是 "ls"argv[1] 是 "-a"argv[2] 是 "-b"argv[3] 是 "-c"

2)有啥用?为啥要放在这里?

这就得从程序如何根据用户输入执行不同操作来说了。程序自己没法 “主动” 知道你想让它干啥,得靠你在命令行里告诉它。argc 和 argv 就是程序接收你 “指令” 的通道。

  • 以 ls 命令为例,ls 本身能列出目录内容,但加上 -a 就会显示隐藏文件,加上 -l 会显示详细信息。ls 程序内部是怎么知道你加了 -a 还是 -l 呢?就是通过 argv 里的内容来判断的。
  • 程序开发者在写 ls 的代码时,会去检查 argv 里的元素。比如看到 argv 里有 "-a",就执行 “显示隐藏文件” 的逻辑;看到有 "-l",就执行 “显示详细信息” 的逻辑。而 argc 能告诉程序一共接收到了多少个参数,方便程序去遍历 argv 数组里的内容。

3)谁需要?

编写需要   根据命令行参数执行不同功能的程序的开发者  需要它们。

举个简单的例子,你自己写一个小程序 mycmd,希望它能根据不同参数做不同事:输入 mycmd -h 显示帮助信息,输入 mycmd -v 显示版本信息。这时候你就得在 main 函数里通过 argc 和 argv 来获取用户输入的参数,然后编写对应的逻辑。

比如下面这个简单的 C 程序:

#include <stdio.h>
int main(int argc, char *argv[]) {if (argc > 1) {if (strcmp(argv[1], "-h") == 0) {printf("这是帮助信息~\n");} else if (strcmp(argv[1], "-v") == 0) {printf("版本 1.0\n");} else {printf("未知参数:%s\n", argv[1]);}} else {printf("请输入参数,比如 -h 或 -v\n");}return 0;
}

编译运行后,输入 ./mycmd -h,程序就会通过 argv[1] 拿到 "-h",然后执行显示帮助信息的代码;输入 ./mycmd -v,就会显示版本信息。要是没有 argc 和 argv,程序就没法知道你输入的是 -h 还是 -v,也就没法执行不同的功能啦。

举例:编写下面的C程序

#include <stdio.h>
#include <string.h>int main(int argc, char *argv[])
{if(argc != 2){printf("Usage: %s[-a|-b|-c]\n",argv[0]);return 1;}const char* arg = argv[1];if(strcmp(arg,"-a")==0)printf("这是功能1\n");else if(strcmp(arg,"-b")==0)printf("这是功能2\n");else if(strcmp(arg,"-c")==0)printf("这是功能3\n");elseprintf("Usage: %s[-a|-b|-c]\n",argv[0]);// for(int i = 0;i<argc;i++)// {//     printf("argv[%d]:%s\n",i,argv[i]);// }      return 0;
}

上面的小例子,我们可以了解到 命令的选项去匹配对应功能的基本方式,

1.2 访问二进制程序

我先把概念输出 

那么意思就是,系统的二进制程序(ls,pwd这样的命令)是放在了环境变量里面,bash加载完之后,如果执行环境变量的指令,bash是支持的;但是我们的程序没有放在环境变量里,就执行不了,所以,放在环境变量里面就可以执行了吗?

试试看!!!!

我把上面执行的指令,一条条写在下面,避免看不清楚:

所以,难道我不想加 ./ 的方式去访问自己的二进制程序,就把自己的二进制程序,一股脑的全部放在 /usr/bin/目录下,就ok了吗?

所以,我们还是删了放在 /usr/bin目录下的指令吧!!!

二、环境变量

2.1 打印环境变量表

打印整个环境变量表:  env

呈现出来的是整个环境变量表!!!

查看环境变量的内容:  echo $name                                  //(name:你环境变量的名称)

通过名称来         标识      环境变量的唯一性

想把自己实现的 code 的二进制可执行程序 , 放到系统的环境变量里 : 

如何恢复?

1) PATH=之前查到的环境变量的内容

2)其实没多大影响,因为环境变量 , 它是内存级的变量 , 在当前bash里的进程上下文里(bash开了一块空间用来存放),关掉xshell , 再查查 , 可以发现,它自己就恢复了

但是,我就是想让自己的路径添加到环境变量里面,同时,不影响系统本身的环境变量,咋办?

2.2 如何理解环境变量

你可以把环境变量理解成 bash(命令行解释器)维护的一张 “全局信息表”,里面存着系统运行、程序执行需要的各种关键信息(比如PATHHOMESHELL等)。

以 ls 命令为例,当你在终端输入 ls -a -b 时:

  1. bash 先拆命令:把 ls-a-b 拆成 “命令行参数”,存在命令行参数表里;
  2. bash 查环境变量表:为了找到 ls 程序在哪,bash 会去环境变量表里找 PATH 变量 ——PATH 里存着系统找命令的所有路径(比如/usr/bin/bin等),bash 会按这些路径挨个找 ls 程序,找到后就执行它。

简单来说,环境变量是 bash 给所有程序准备的 “共享信息库”,程序运行时需要的全局配置、路径、用户信息等,都从这张 “表” 里拿。

2.3 环境变量从哪里来?

1. 系统配置文件:环境变量的 “初始模板”

Linux 系统里有一系列配置文件,比如 /etc/profile~/.bashrc~/.bash_profile 等。这些文件里写着系统默认的环境变量配置(比如PATH的默认路径、LANG语言设置等)。

当你登录系统时,bash 会自动读取这些配置文件,把里面的环境变量加载到自己的 “环境变量表” 里。比如 ~/.bashrc 是每个用户自己的配置文件,你在里面加 export MYVAR=123,下次登录时,bash 的环境变量表就会包含 MYVAR 这个变量。

2. 进程上下文:每个 bash 实例的 “专属副本”

如果有 10 个用户同时登录系统,就会有10 个独立的 bash 进程(每个用户一个)。每个 bash 进程都会从系统配置文件里读取环境变量,然后在自己的 “进程上下文” 里存一份副本

这意味着:每个 bash 进程的环境变量是 “独立维护” 的。比如用户 A 在自己的 bash 里改了PATH,不会影响用户 B 的 bash 里的PATH—— 就像 10 个人各拿一本 “信息手册”,自己改自己的,互不干扰。

总结一下逻辑链

系统配置文件 → bash 读取配置 → 每个 bash 进程生成自己的 “环境变量表” → 程序运行时从所属 bash 的环境变量表中获取信息。

2.4 解释windows里装软件的时候为啥要加环境变量

一、先想清楚:“不配置环境变量会怎样?”

假设你装了一个软件(比如 Python),它的可执行文件 python.exe 放在 C:\Python311\ 目录下。如果不配置环境变量,每次运行 Python 时,你得在命令行里输入完整路径

C:\Python311\python.exe 你的脚本.py

这显然很麻烦 —— 要是软件有很多可执行程序(比如编译器、工具链),每次都输全路径根本不现实。

二、配置环境变量的核心作用:“让系统自动找程序”

环境变量里的 PATH 就像 Linux 里的 PATH 一样,是系统查找可执行程序的 “路径列表”。当你把软件的安装路径加到 PATH 里后:

  • 系统会按照 PATH 里的路径挨个查找你输入的命令(比如 python);
  • 一旦在某个路径(比如 C:\Python311\)里找到 python.exe,就会直接执行,不需要你再输全路径。

三、结合 “用户变量 vs 系统变量” 的就近原则

Windows 里的环境变量分为用户变量系统变量

  • 用户变量只对当前用户生效,优先级更高(就近原则);
  • 系统变量:对所有用户生效,优先级更低。

装软件时配置环境变量,本质是把软件的可执行路径 “注册” 到系统的 “查找列表” 里,让系统能自动定位到程序。比如装 Python 时,把 C:\Python311\ 加到 PATH 变量里,之后你在任何目录下输 python,系统都会在 PATH 列表里找到它并执行。

2.5 常见的环境变量

每一个环境变量都会有对应的功能,不同环境变量,功能不同!!!

HOME

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

SHELL

SHELL : 显示当前版本的shell

USER

USER: 当前登录的用户名(是谁登录就是谁!!!)

不同的用户登录,bash会把用户记录下来!!!

我们在env后,可以发现有一个USER,有一个LOGNAME , 它们有什么区别?

  • USER:表示当前正在操作的用户,是 “动态身份”。比如你用 su 切换到其他用户后,USER 会变成新用户的名字。
  • LOGNAME(你说的 “localname”):表示最初登录系统的用户,是 “静态身份”。哪怕你用 su 切换了用户,LOGNAME 还是保持登录时的原始用户名。

HISTORY

HOSTNAME

显示当前主机名字

SHH_CLIENT

当前在哪一个用户端登录

TERM

终端类型

PWD

当前shell所在的路径

OLDPWD

记录上一次的路径

也就是cd .. : 返回上级目录 、cd - : 返回上一次执行的目录的逻辑 

2.6 环境变量的相关操作

1)查看

env : 查看环境变量表

echo $xxx : 查看某一个环境变量

2)设置一个新的环境变量

3)清除环境变量

三、如何获取环境变量(代码)

3.1 命令行的第三个参数

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

3.2 通过getenv()

#include <stdio.h>
#include <string.h>
#include <stdlib.h>int main(int argc, char *argv[])
{(void)argc;(void)argv;(void)env;char *environ = getenv("PATH");if(value==NULL)return 1;printf("PATH->%s\n",value);return 0;
}

#include <stdio.h>
#include <string.h>
#include <stdlib.h>int main(int argc, char *argv[])
{(void)argc;(void)argv;(void)env;char *who = getenv("USER");if(who==NULL)return 0;if(strcmp("who","zs")==0){printf("这是程序的正常执行逻辑\n");}else{printf("Only zs!!!\n");}return 0;
}

3.3 通过第三方变量environ获取

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

四、环境变量通常有全局性

环境变量具有全局性,能被所有子进程继承

shell 不仅仅支持环境变量,还支持本地变量

但是,如果我们env , 是查不到i , 因为i 是本地变量 , 那么 , 如何查看本地变量呢???

使用set !!!!

从上面我们可以知道,bash会记录两套变量,一个环境变量,一个本地变量;

那么本地变量有什么用呢?bash为什么支持环境变量呢?

如何把我们的本地变量,放在环境变量里面呢?

我们可以env , 看到我们的本地变量被放在了环境变量里面!为什么呢?

1)先明确几个概念

  • 本地变量:只在当前 bash 会话里生效,子进程(比如你执行的lsgrep这些命令)看不到它。比如你在终端里写i=100,这个i就是本地变量,只有当前 bash 自己知道。
  • 环境变量:通过export命令 “升级” 后,子进程能看到它。比如export i=100后,i就变成环境变量,你再执行的子进程(如echo $i)就能读到这个值。
  • 内建命令(builtin command):像exportcdsource这些命令,是bash 自己内置的功能,不需要创建 “子进程” 来执行,直接由 bash 自己完成。

2)为什么export能让本地变量变成 “子进程可见”?

export i,是把本地变量i“升级” 成环境变量的过程。

  • 因为export内建命令,它不需要创建子进程,而是由bash 自己直接修改 “环境变量表”
  • 当你执行export i后,i就从 “本地变量” 变成了 “环境变量”,此时所有由当前 bash 创建的子进程(比如你后续执行的pythonlsecho $i等命令)都能读到i的值。

三、反过来:子进程能给父进程传变量吗?

不能!这是 Linux 进程模型的 “规则”:子进程无法主动修改父进程的变量。

比如你在 bash 里执行一个程序myprogmyprog里给i赋值,这个修改只能在myprog自己的进程里生效,不会影响父进程(bash)里的i

总结一下逻辑

  • 本地变量是 bash 的 “私有变量”,子进程看不到;
  • export是内建命令,由 bash 自己执行,把本地变量 “升级” 成环境变量,让子进程能看到;
  • 子进程永远无法主动修改父进程的变量,这是进程的 “隔离性” 决定的。

简单来说,export是 bash 的 “内部操作”,能让变量 “传给子进程”;但子进程没法 “反向传给父进程”~

http://www.dtcms.com/a/517121.html

相关文章:

  • Java 序列化和Scala的闭包的区别和注意点
  • 莘庄做网站视频直播怎么赚钱的
  • 南昌网站seo公司电商网站的功能
  • 注销之后logonui.exe依然有事情要做
  • 短租网站那家做的好处富力海外网络推广
  • 【C++ STL 深入解析】insert 与 emplace 的区别与联系(以 multimap 为例)
  • 文件系统LittleFS
  • day16_接口加强练习
  • 潍坊中脉网站建设公司做个网站多少钱一个月
  • PHP+Ajax网站开发典型实例3d建模自学
  • 雪崩阵列中的多域物理串扰模型
  • 注册公司网站模版怎么自己做网页
  • 四网合一的网站个人网站可以做推广吗
  • 做网站是用wordpress还是DW谷歌海外推广怎么做
  • 蛋白表达系统的技术布局与应用
  • C++11 核心新特性:从语法重构到工程化实践
  • C# 上传票据文件 调用Dify的API完成OCR识别
  • 交换机Super密码配置方法(V7
  • 做网站的实施过程足球梦网站建设的基本思路
  • 安阳市住房和城乡建设厅网站华为做网站
  • 欧普建站网页设计与网站建设全攻略
  • 怎么优化自己网站wordpress文章不显示图片
  • 网站公司建立网页设计素材哪里找
  • 网站友情链接交易平台wordpress首页模块排序权限修改
  • 下列哪一项不属于电子商务网站建设网站标题作弊详解
  • 网络故障排查三板斧:路由追踪、端口检查,快速定位网络问题
  • 一站式服务平台官网wordpress后台字体修改
  • Flink状态编程之算子状态(OperatorState)
  • 哔哩哔哩修改版 8.64.0| 去除多项冗余内容和广告,精简流畅好用
  • 如何写网站建设报告3d动画制作流程