[Linux](7)环境变量

环境变量概念

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

例如我们编写的代码在链接的时候,我们并不知道要链接的动态库静态库在哪里,但是照样可以链接成功,原因就是有相关的环境变量帮助编译器进行查找。

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

环境变量初识:PATH

❓为什么我们的代码运行要带路径,而系统的指令不用带路径?

  • 因为系统中存在相关的环境变量,保存了程序的搜索路径

输入 env 查看所有环境变量。

系统中搜索可执行程序的环境变量叫做 PATH

[CegghnnoR@VM-4-13-centos ~]$ env | grep PATH
LD_LIBRARY_PATH=:/home/CegghnnoR/.VimForCpp/vim/bundle/YCM.so/el7.x86_64
PATH=/usr/local/bin:/usr/bin:/usr/local/sbin:/usr/sbin:/home/CegghnnoR/.local/bin:/home/CegghnnoR/bin

也可以通过 echo $PATH 查看:

[CegghnnoR@VM-4-13-centos ~]$ echo $PATH
/usr/local/bin:/usr/bin:/usr/local/sbin:/usr/sbin:/home/CegghnnoR/.local/bin:/home/CegghnnoR/bin

PATH 内有多个路径,以 : 作为分隔符。

当我们输入指令后,就会在这些路径中一个一个地搜索,直到找到该指令的可执行程序。

而我们自己写的程序,不在PATH的路径中,所以要自己带上路径。

❓如何能让自己写的程序运行也不带路径呢?

  1. 我们当然可以把自己的可执行程序粘贴到 PATH 的某个路径的底下,不过要在 root 下或者 sudo。我们不建议这样做。

  2. 可以在 PATH 下增加新的路径,export PATH=$PATH:[绝对路径],这样该路径下的可执行程序运行就不用带路径了。

  3. PATH 改错了没关系,退出重新登陆就恢复了。

常见环境变量

MANPATH:man 手册的搜索路径

HOSTNAME:主机名

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

HISTSIZE:能保存的历史命令条数

USER:当前用户名

MAIL:邮箱路径

PWD:当前所处路径

LANG:当前采用的编码格式

HOME:当前用户对应的家目录

LOGNAME:登陆用户

相关命令

echo:显示环境变量

export:设置一个新的环境变量,或者将本地变量导出为环境变量

env:显示所有环境变量

unset:清除环境变量

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

在命令行中不加 export 直接定义的变量叫做本地变量,它是局部的。

环境变量的C/C++获取方式

main函数参数

我们知道 main 函数可以带两个参数:int argc, char* argv[]

第二个参数是一个指针数组,第一个参数表示这个数组的大小。

它们被称作命令行参数,传递的是命令行中输入的程序名和选项。

我们可以打印里面的内容看一下:

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

结果:

[CegghnnoR@VM-4-13-centos 2022_8_14]$ ./mytest
argv[0]:./mytest
[CegghnnoR@VM-4-13-centos 2022_8_14]$ ./mytest -a
argv[0]:./mytest
argv[1]:-a
[CegghnnoR@VM-4-13-centos 2022_8_14]$ ./mytest -a -b -c
argv[0]:./mytest
argv[1]:-a
argv[2]:-b
argv[3]:-c

argv 数组的最后一个以 NULL 结尾。

利用这个,我们可以实现一个命令行上的计算器:

#include <stdio.h>
#include <unistd.h>
#include <string.h>
#include <stdlib.h>

int main(int argc, char* argv[])
{
    if (argc != 4)
    {
        printf("Usage: %s [-a|-s|-m|-d] [one_data] [two_data]\n", argv[0]);
        return 0;
    }
    int x = atoi(argv[2]);
    int y = atoi(argv[3]);
    if (strcmp("-a", argv[1]) == 0)
    {
        printf("%d + %d = %d\n", x, y, x + y);
    }
    else if (strcmp("-s", argv[1]) == 0)
    {
        printf("%d - %d = %d\n", x, y, x - y);
    }
    else if (strcmp("-m", argv[1]) == 0)
    {
        printf("%d * %d = %d\n", x, y, x * y);
    }
    else if (strcmp("-d", argv[1]) == 0 && y != 0)
    {
        printf("%d / %d = %d\n", x, y, x / y);
    }
    else
    {
        printf("Usage: %s [-a|-s|-m|-d] [one_data] [two_data]\n", argv[0]);
    }
    return 0;
}

结果:

[CegghnnoR@VM-4-13-centos 2022_8_14]$ ./mycal
Usage: ./mycal [-a|-s|-m|-d] [one_data] [two_data]
[CegghnnoR@VM-4-13-centos 2022_8_14]$ ./mycal -a 21 34
21 + 34 = 55
[CegghnnoR@VM-4-13-centos 2022_8_14]$ ./mycal -s 21 34
21 - 34 = -13
[CegghnnoR@VM-4-13-centos 2022_8_14]$ ./mycal -m 21 34
21 * 34 = 714
[CegghnnoR@VM-4-13-centos 2022_8_14]$ ./mycal -d 28 4
28 / 4 = 7

那么我们讲这个的意义是什么呢?

通过这个,我们可以意识到:Linux系统中,同一个命令给与不同的选项会有不同的表现,这也是指令中这么多选项的由来和起作用的方式。


三种环境变量获取方式

其实 main 函数还可以带第三个参数 char* env[] ,它表示的就是环境变量

#include <stdio.h>

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

结果非常长,不过它和我们使用指令 env 显示出来的是一样的。

这说明:一个进程是会被传入环境变量参数的。

C语言细节:一个没有参数列表的函数是可以被传入参数的,只不过未被使用。如果参数列表显式写上 void 则无法传参。

除了上面获得环境变量的方式,我们还可以这样:

#include <stdio.h>

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

第三种获得环境变量的方式:

直接使用 getenv() 函数

#include <stdio.h>
#include <stdlib.h>

int main()
{
    char* val = getenv("PATH");
    printf("%s\n", val);
    return 0;
}

为什么要获取环境变量?

因为环境变量中的值是有意义的。

比如我们可以通过USER环境变量来控制程序的运行权限:

下面这个程序,只有我能运行 if 语句后面的部分,其他用户都不行(甚至连 root 也不行,除非他改我代码):

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
int main()
{
    char* id = getenv("USER");
    if (strcmp(id, "CegghnnoR") != 0)
    {
        printf("权限拒绝!\n");
        return 0;
    }
    printf("成功执行\n");
    return 0;
}

环境变量的全局性

我们知道,命令行中启动的进程,其父进程都是 bash

如果我们随便获取一个不存在的环境变量:

#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>

int main()
{
    printf("Hello world, pid:%d, ppid:%d, myenv:%s\n", getpid(), getppid(), getenv("nihao"));
    return 0;
}
[CegghnnoR@VM-4-13-centos 2022_8_14]$ ./mytest
Hello world, pid:30517, ppid:26920, myenv:(null)

结果为null

CegghnnoR@VM-4-13-centos 2022_8_14]$ nihao=11112222333
[CegghnnoR@VM-4-13-centos 2022_8_14]$ ./mytest
Hello world, pid:30921, ppid:26920, myenv:(null)

创建一个本地变量,结果依然为null

[CegghnnoR@VM-4-13-centos 2022_8_14]$ export nihao
[CegghnnoR@VM-4-13-centos 2022_8_14]$ ./mytest
Hello world, pid:31480, ppid:26920, myenv:11112222333

将它导出为环境变量,可以成功显示环境变量的值。

这说明,环境变量是会被子进程继承下去的。

而本地变量,本质就是在 bash 内部定义的变量,不会被子进程继承下去。

残留问题

定义的本地变量可以使用 echo 打印,export 导出

[CegghnnoR@VM-4-13-centos 2022_8_14]$ nihao=22
[CegghnnoR@VM-4-13-centos 2022_8_14]$ echo $nihao
22
[CegghnnoR@VM-4-13-centos 2022_8_14]$ export nihao

❓echo 和 export 都是命令,不也是子进程吗,那么它们是怎么获得本地变量的呢?

其实 Linux 下大部分命令都是通过子进程的方式执行的,

但是,还有一部分命令,不通过子进程的方式执行,而是由 bash 自己执行(调用自己对应的函数来完成)。

我们把这种命令叫做内建命令

  • 10
    点赞
  • 11
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 9
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 9
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

世真

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值