进程之环境变量

本篇目标:

理解环境变量,熟悉常见环境变量及相关指令

一.环境变量

1.概念

引子:

我们可能会有这样的疑问:我们在编写C/C++代码的时候,在链接的时候,从来不知道我们的所链接的动态静态库在哪里,但是照样可以链接成功,生成可执行程序,原因就是有相关环境变量帮助编译器进行查找,当然今天讲的并不是动静态库,以后会讲的,那什么是环境变量呢?

环境变量(environmentvariables)⼀般是指在操作系统中用来指定操作系统运行环境的⼀些参数,但是光是这样说,肯定是不明不白地,下面就由浅入深的讲解它。

2.命令行参数

先别急着了解环境变量,可以先了解一下命令行参数。

2.1.概念

命令行参数 就是你在启动程序时,直接在程序名称后面输入的附加信息,例如我们常用的ls -l中的-l就是命令行参数,而ls 就是命令本身,下面用一个我们可能没见过的c语言代码演示一下

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

int main(int argc, char* argv[]) 
{
    //...
    return 0;
}

main函数其实也是有参数的,而参数中的argc其实就是个计数器,用来记录程序的命令行参数总数

它永远至少是 1, 因为即使没输入任何参数,程序本身的名字也会占用一个位置。

argv是一个指向变长字符串数组的指针,每个字符串代表一个命令行参数,在程序启动时,操作

系统会将命令行字符串拆分,存储在进程的用户栈空间内,并由argv指向这些地址,如果没有命令

行字符串,那么argv[0]就默认是程序本身的名字

代码演示:

code.c中:

cpp 复制代码
#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中:

cpp 复制代码
code:code.c
    gcc -o $@ $^ -std=c99 
                                                     
PHONY:clean
clean:
    rm -rf code

输出结果:

可以看出,当我们输入额外的-a/-b/-c时,额外的-a/-b/-c都会被填进到argv所指向的变长字符串数

组中,所以假设我们输入./code -a -b -c时,就会创建这个表,如图:

那么是谁在做这件事呢?答案就是bash,Bash 将我们输入的每一个字符以空格分隔来依次存入了这张表中,下面用代码来加深我们的理解:

cpp 复制代码
#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即可查看所有的环境变量,如图:

下面讲解一下PATH

3.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>.USERLOGNAME 都是 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)

cpp 复制代码
#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 MYENV1=11111,export MYENV2=22222,export MYENV3=33333,在env就如图所示:

可以看出我们自己创建的环境变量导入到了bash里面,此时在运行code,就会如图所示:

所以我们可以得出结论:父进程的环境变量可以被子进程继承,所有的进程都可以拿到环境变量,所以这也可以证明环境变量具有全局性。

5.2.2.通过第三方变量environ

cpp 复制代码
#include<stdio.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获取

cpp 复制代码
#include <stdio.h>
#include <stdlib.h>
int main()
{
    printf("%s\n", getenv("PATH"));
    return 0;
}

如果我们通过export来创建环境变量,例如export MYENV1=11111,export MYENV2=22222,export MYENV3=33333,在env就如图所示:

可以看出我们自己创建的环境变量导入到了bash里面,

此时,我们就可以创建一个只可以当前用户可以使用的程序,例如:

cpp 复制代码
#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;
}
相关推荐
Wanliang Li2 小时前
Linux驱动——input子系统
linux·驱动开发·input
feng_you_ying_li2 小时前
liunx之make/makefile的使用
linux
默|笙2 小时前
【Linux】线程概念与控制(4)_线程封装
linux
仍然探索未知中2 小时前
【Linux内核源码分析】内核数据结构
linux·数据结构
chxii2 小时前
linux 下用 acme.sh 搞定 Nginx 免费 SSL 证书自动续期(下) 对于acme.sh命令安装详解
linux·运维·服务器
Bert.Cai3 小时前
Linux more命令详解
linux·运维
minji...3 小时前
Linux 多线程(四)线程等待,线程分离,线程管理,C++多线程,pthread库
linux·运维·开发语言·网络·c++·算法
麦德泽特3 小时前
基于 Go 语言的 Modbus 项目实战:构建高性能、可扩展的工业通信服务器
服务器·开发语言·golang·modbus·rtu
倔强的胖蚂蚁3 小时前
云原生服务器存储规划与磁盘选型实施
运维·服务器·云原生