Linux 环境变量

目录

一、环境变量的基本概念

1.常见环境变量

2.查看环境变量方法

​3.几个环境变量

环境变量:PATH

环境变量:HOME

环境变量:SHELL

二、和环境变量相关的命令

三、库函数getenv,setenv

四、环境变量和本地变量

五、命令行参数

[1.main 函数可以带参数吗?能带几个参数呢?](#1.main 函数可以带参数吗?能带几个参数呢?)

2.命令行参数的意义

六、环境变量的组织方式

[1、通过 main 的第三个参数获取环境变量](#1、通过 main 的第三个参数获取环境变量)

[2、通过全局变量 environ 获取环境变量](#2、通过全局变量 environ 获取环境变量)


一、环境变量的基本概念

在我们学习JAVA,Python我们都要在windows上配置环境变量。

环境变量的概念

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

1.常见环境变量

  • PATH : 指定命令的搜索路径
  • HOME : 指定用户的主工作目录(即用户登陆到Linux系统中时,默认的目录)
  • SHELL : 当前Shell,它的值通常是/bin/bash。

2.查看环境变量方法

echo $NAME //NAME:你的环境变量名称

3.几个环境变量

环境变量:PATH

我们先先创建一个文件:test.c,并写入代码。

cpp 复制代码
 #include <stdio.h>
   int main()
   {
    printf("打印\n");                                                                                                                                                                                           
     return 0;
   }

我们生成的可执行程序是不是一条命令呢?

是一条命令,每一个可执行文件都具有(X)执行权限。

像我们常说的命令,指令,可执行程序 都是同一个概念。

那竟然mytest是一条命令,那为什么会出现无法找到mytest这个指令呢?而是要./mytest呢?

我们上面说PATH环境变量是指令的搜索路径

这些都是绝对路径,如果在这些路径下找不到该指令的话,就会报错!

如果我们想直接用mytest让程序运行起来该怎么办呢?

我们可以将该可执行程序的路径添加到环境变量PATH中

这样我们就可以直接用mytest运行了。

环境变量:HOME

分别在 root 和普通用户下执行 cd ~ 和 pwd 查看家目录,分别是 /root 和 /home/xyl,为什么得到的结果不一样呢?

因为不同用户的家目录中的配置文件不一样,所以不同用户下的环境变量 HOME 也是不一样的。

环境变量:SHELL

  • 我们在命令行上运行的大部分命令,它们的父进程都是 bash。
  • bash 创建子进程,然后由子进程执行用户输入的命令。

二、和环境变量相关的命令

1. echo: 显示某个环境变量值
2. export: 设置一个新的环境变量

3. env: 显示所有环境变量
4. unset: 清除环境变量

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

三、库函数getenv,setenv

getenv:char *getenv(const char *name); 获取环境变量。

setenv:int setenv(const char *name, const char *value, int overwrite);更改或添加环境变量。

getenv() 和setenv()

cpp 复制代码
1 #include <stdio.h>
  2 #include <stdlib.h>
  3 int main()
  4 {
  5   printf("%s\n",getenv("PATH"));
  6   char* env;
  7   env=getenv("HOME");
  8   printf("HOME:%s\n",getenv("HOME"));
  9   setenv("HOME","haha",1);
 10 
 11   printf("HOME:%s\n",getenv("HOME"));                                                                                                                            
 12   return 0;
 13 }

setenv()用来改变或增加环境变量的内容。参数name为环境变量名称字符串。参数 value则为变量内容,参数overwrite用来决定是否要改变已存在的环境变量。如果没有此环境变量则无论overwrite为何值均添加此环境变量。若环境变量存在,当overwrite不为0时,原内容会被改为参数value所指的变量内容;当overwrite为0时,则参数value会被忽略。返回值 执行成功则返回0,有错误发生时返回-1。

四、环境变量和本地变量

上面我们说环境变量具有全局属性,也就是说环境变量可以被子进程继承。

cpp 复制代码
1 #include <stdio.h>
  2 #include <stdlib.h>
  3 int main()
  4 {
  5   char* env=getenv("MYENV");
  6   if(env)
  7   {
  8     printf("%s",env);                                                                                                                        
  9   }                                                                                                                                    
 10   return 0;                                                                                                                            
 11 } 

运行发现没有结果,因为我自己创建的MYENV不是环境变量。

当我们用export导出环境变量时,发现程序运行并打印了。

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

  • 本地变量(只能在当前 shell 命令行解释器内被访问,不可以被子进程继承)

这说明本地变量不能被子进程继承

我们该如何查看本地变量呢?

其实和环境变量是一样的。

上面说到,我们在命令行上运行的大部分命令,都是 bash 创建子进程来执行的,而本地变量不能被子进程继承,那为什么使用 echo 命令,却可以访问本地变量呢?

因为echo是一个内建命令,是shell程序内部的一个函数,可以直接访问shell内定义的本地变量,这并没有fork创建子进程。

五、命令行参数

main函数,我们很少见到像这样的类型。

cpp 复制代码
int main(int argc, char* argv[])。

1.main 函数可以带参数吗?能带几个参数呢?

main 函数可以带参,但大部分都是缺省。

  • argc:命令行参数的个数。
  • argv:字符指针数组(指向各个命令行参数的字符指针所构成的数组)。
cpp 复制代码
int main(int argc, char* argv[]) // 接收命令行参数
{
    for (int i = 0; i < argc; i++)
    {
        printf("argv[%d]: %s\n", i, argv[i]); // 遍历字符指针数组argv
    }
    return 0;
}

运行结果:字符数组中只有一个元素,就是我们输入的命令。

如果我们多输入几个参数

实际上我们输入的命令行参数,就是一个个的 C 字符串: "./proc"、"arg1"、"arg2"、"arg3",传给了 main 函数:

2.命令行参数的意义

为什么要存在命令行参数呢?

帮助我们能够给同一个程序,设计出不同的业务功能。

举个小例子,比如我想要实现这样一个计算器:

  • 如果输入 ./cal,则会提示该程序的正确用法:Usage:./cal -[a|s] x y;
  • 输入 ./cal -a 1 2,cal 程序可以输出 1 + 2 的结果;
  • 输入 ./cal -s 4 2,cal 程序可以输出 4 - 2 的结果。
cpp 复制代码
#include <stdio.h>
#include <stdlib.h> // atoi -- 函数原型:int atoi(const char *nptr); // 将C字符串转换成整数
#include <string.h> // strcmp
 
// cal命令的用法手册
void Usage(const char* cal)
{
    printf("Usage: %s -[a|s] x y\n", cal);
}
 
int main(int argc, char* argv[]) // 接收命令行参数
{
    // 输入的参数个数不为4
    if (argc != 4)
    {
        Usage(argv[0]);
        return 1; // 退出程序
    }
 
    // 保存第3个和第4个参数                                                      
    int x = atoi(argv[2]);
    int y = atoi(argv[3]);
    
    // 根据不同参数,执行不同功能,然后输出结果
    if (strcmp(argv[1], "-a") == 0)
    {                                            
        printf("%d + %d = %d\n", x, y, x + y); 
    }
    else if (strcmp(argv[1], "-s") == 0)
    {
        printf("%d - %d = %d\n", x, y, x - y); 
    }
    else
    {
        Usage(argv[0]);
        return 1; // 退出程序
    }
 
    return 0;
}

命令行参数可以让同一个命令,通过带上不同的选项表现出不同的功能和作用。

比如:ls -l、ls -l -a、ls -l -a -i。这就是命令行参数的意义。

总结:我们运行的进程,都是子进程,bash本身在启动时,会从操作系统的配置文件读取环境变量信息,子进程会继承父进程的环境变量

可以通过 main 函数的参数,可以传递命令行参数和环境变量

六、环境变量的组织方式

main 函数除了可以传递两个和命令行参数相关的参数 argc 和 argv 以外,还可以传递第 3 个参数 env

cpp 复制代码
int main(int argc, char* argv[], char* env[]);

这也是 main 函数获取环境变量的方式。

通过给 main 函数第三个参数传参,把一个个环境变量传递给当前程序,当前程序运行起来变成进程,就意味着当前这个进程获取到了这些环境变量。

每个被 bash 创建的子进程都会接收到一张环境表,环境表是一个字符指针数组,每个指针指向一个以 '\0' 结尾的环境字符串(环境变量)。

1、通过 main 的第三个参数获取环境变量

cpp 复制代码
// proc.c
#include <stdio.h>
#include <string.h>
 
int main(int argc, char* argv[], char* env[]) // 通过第三个参数接收环境变量
{
    for (int i = 0; env[i]; i++) // 循环结束条件为env[i],遍历到NULL停止
    {
        printf("env[%d]: %s\n", i, env[i]); // 遍历字符指针数组env
    }
    return 0;
}

我们获取了bash进程的所有环境变量,因为子进程mytest继承了bash进程的环境变量。

2、通过全局变量 environ 获取环境变量

C/C++ 提供了一个全局二级指针变量 char** environ,指向存放环境变量地址的字符指针数组 char* env[ ]。

cpp 复制代码
#include <stdio.h>
 
int main()
{
    extern char** environ;
    for (int i = 0; environ[i]; i++)
    {
        printf("%s\n", environ[i]); // 等价于 *(environ + i)
    }
    return 0;
}

因为 libc 中定义的全局变量 environ 指向环境变量表,environ 没有包含在任何头文件中,所以在使用时要用 extern 声明。

相关推荐
HaoHao_01020 分钟前
AWS Snowball
服务器·云计算·aws·云服务器
小林想被监督学习25 分钟前
RabbitMQ 仲裁队列 -- 解决 RabbitMQ 集群数据不同步的问题
linux·分布式·rabbitmq
xf8079891 小时前
cursor远程调试Ubuntu以及打开Ubuntu里面的项目
linux·运维·ubuntu
dot to one1 小时前
Linux 入门 常用指令 详细版
linux·服务器·centos
Golinie2 小时前
记一次Linux共享内存段排除Bug:key值为0x0000000的共享内存段删除不了
linux·bug·共享内存段
狄加山6752 小时前
Linux 基础1
linux·运维·服务器
Once_day2 小时前
Linux-arm(1)ATF启动流程
linux·arm开发
测试冲鸭2 小时前
【可实战】Linux 系统扫盲、 Shell扫盲(如何写一个简单的shell脚本)
linux·运维·arm开发
Zfox_3 小时前
HTTP cookie 与 session
linux·服务器·网络·c++·网络协议·http
余额很不足3 小时前
K8S知识点
linux·容器·kubernetes