【Linux系统】第十节—【进程概念】环境变量 | 详解,包会!

Hello,我是云边有个稻草人---csdn个人主页,与你分享Linux领域专业知识,今天继续学习环境变量。

《Linux系统》本篇文章所属专栏---持续更新中---欢迎订阅!

目录

四、环境变量

1、概念介绍

【命令行参数】

2、一个例子,一个环境变量

【引入环境变量--->PATH】

【如何理解环境变量呢?存储的角度】

【环境变量,最开始是从哪里来的?】

3、认识更多的环境变量

4、获取环境变量的方法

【命令操作】

【通过代码如何获取环境变量】

5、理解环境变量的特性


正文开始------

【进程概念】相关知识回顾:

【Linux系统】第八节---进程概念(上)---冯诺依曼体系结构+操作系统+进程及进程状态+僵尸进程---详解!-CSDN博客

【Linux系统】第九节---进程状态续集+进程优先级+进程切换-CSDN博客

四、环境变量

1、概念介绍

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

首先了解什么是命令行参数

【命令行参数】

2、一个例子,一个环境变量

【引入环境变量--->PATH】

为什么执行我们自己的的时候要带路径**./** ,而执行系统命令的时候就不需要带**./** ?因为我们创建的程序在当前路径下,而系统命令有环境变量来帮助系统找到对应的命令。

2.1 要执行一个程序,必须先找到它!

2.2 系统中存在环境变量PATH(系统中搜索指令的默认搜索路径),来帮助系统找到目标二进制文件!

/usr/bin 是 Linux 里绝大多数用户日常命令和应用程序的存放地,全是可执行的二进制文件,所有用户都能运行。

是不是将我们自己创建的命令放到 /usr/bin 路径下就可以直接执行了呢?是的,放到这个路径下面系统可以自动就能找到。强烈不建议将我们自己的命令放到该路径下,执行rm /usr/bin/名字 删掉。

为什么系统知道从这个路径下面找到对应的二进制文件呢? 因为环境变量 PATH(系统中搜索指令的默认搜索路径)!PATH下面有/usr/bin 路径,见下:

**env:打印当前系统所有环境变量,格式:名称=内容。**我们使用env确实查到了环境变量PATH,见下:

查看环境变量中具体某一个环境变量:echo $PATH

所以当我们执行 ls 命令时,系统会首先到环境变量PATH下找,按顺序在每个目录下匹配名为ls的可执行文件,找到首个匹配文件就加载运行,遍历全部路径仍未找到,提示 command not found

那是不是将我们自己放命令的路径放到PATH里面是不是系统就可以直接找到我们自己创建的路径呢?是的!

PATH=$PATH:自己存放命令的路径

此时执行自己的程序就可以不带路径了。当我们重新启动Xshell后PATH里面的内容被重置。

【如何理解环境变量呢?存储的角度】

是存储在bash进程的上下文里面的

所以bash内部有两张表!命令行参数表,环境变量表。

但是,如果无人登录,那么环境变量还有没有呢?环境变量在哪里呢?

【环境变量,最开始是从哪里来的?】

系统的相关配置文件里来的!Bash 启动时读取配置文件,通过 malloc 在自身进程内构建环境变量表。

最后,如果Linux系统有10用户登录呢?存在10个bash。

我们开头讲的,执行一个程序,我们必须先找到它,谁找?bash,通过PATH来找(环境变量)。

可以自己梳理一下整个的动态过程。


3、认识更多的环境变量

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

如何生成的

用户登录系统、启动 bash 时:系统读取用户信息 + bash 配置文件,自动在bash 进程上下文的环境变量表 中,写入 HOME=xxx 这一条环境变量。

核心作用

  • 直接输入 cd 回车,会自动进入 HOME 指向的家目录;
  • ~ 波浪号,本质就是 HOME 变量的别名~ 等价于 $HOME;
  • 各类软件、配置文件(.bashrc、.bash_profile)默认都存放于 HOME 目录下

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

  • bash = 主流默认 Shell,是 CentOS、Ubuntu 等系统默认使用的命令解释器。

  • 记录当前终端使用的命令解释器类型。

  1. USER
  • 含义 :记录当前登录操作的用户名
  • 特点 :切换用户后会同步变化,标识当前正在使用终端的用户。
  1. LOGNAME
  • 含义 :记录最初登录系统的原始用户名
  • 特点 :一旦登录就固定不变,就算用 su 切换别的用户,LOGNAME 依然保留最开始登陆的账号。

su 用户名 临时切换;

su - 用户名 完整登录并加载新用户环境配置

HISTSIZE:

限制当前终端会话(内存中) 能保存的历史命令最大条数

bash 复制代码
history        # 查看所有历史命令
history 10     # 只看最近10条
!数字          # 执行对应编号的历史命令
!!             # 重复执行上一条命令
history | wc -l #用于统计历史命令总行数,通过管道将 history 输出交给 wc -l 计数,结果受 HISTSIZE 限制。

hostname # 查看主机名

hostname 新名字 # 临时修改主机名

SSH_CLIENT=客户端IP 客户端端口 服务器SSH端口

SSH_TTY=/dev/pts/0:标记当前远程登录所使用的终端设备

PWD:记录当前工作目录绝对路径,cd 切换目录会自动更新,存放于 Bash 进程上下文,pwd 命令直接读取该变量。

OLDPWD:记录上一次所在的工作目录绝对路径,由 bash 自动维护,存放在进程上下文的环境变量表。

  • 执行 cd 切换目录 时:原来的 PWD 会自动保存为 OLDPWD,再更新新的 PWD
  • 命令 cd - 本质:直接跳转至 $OLDPWD 目录

cd / cd ~ 依赖环境变量 HOME ,作用:直接进入当前用户家目录 ,二者完全等价。
cd - 依赖环境变量 OLDPWD ,作用:快速切换到上一次的工作目录。


4、获取环境变量的方法

【命令操作】

env、echo $XXX

export :设置⼀个新的环境变量。用于将变量导出到 bash 进程的环境变量表,使其能被子进程继承使用。

unset:删除变量,清空环境变量表中指定内容;与 export 相反,一个导出、一个销毁。

【通过代码如何获取环境变量】

方法一:获取环境变量,命令行第三个参数

理解一下:

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

// main 函数的第三个参数 env[]
int main(int argc, char *argv[], char *env[])
{
    int i = 0;
    // 循环遍历 env 数组,直到遇到 NULL(结束标记)
    for(; env[i]; i++){
        printf("%s\n", env[i]);
    }
    return 0;
}

编译运行后,会打印出当前进程所有的环境变量,比如:

bash 复制代码
PATH=/usr/local/bin:/usr/bin:/bin
HOME=/home/yourname
USER=yourname
SHELL=/bin/bash
SSH_CLIENT=...

上面代码里面的 env 是一个 字符串指针数组 ,它的每一个元素,都指向一个形如 KEY=VALUE 的环境变量字符串,数组的末尾以 NULL 作为结束标记。

当你在 bash 中运行这个程序时,bash 会把自己进程上下文里的环境变量表 ,完整复制一份,传给这个程序的 env[] 参数。这就是为什么程序能读到 PATHHOMESSH_CLIENT 这些你在 bash 里看到的变量 ------ 它们都是父进程(bash)传给子进程的。

env 数组的最后一个元素是 NULL,当 env[i]NULL 时,条件不成立,循环自动结束。这是 C 语言中遍历以 NULL 结尾的数组的经典写法。

刚才用 export 往bash的环境变量里面导入几个环境变量,那子进程是否能继承我刚才添加的环境变量呢?可以!可以自己使用上面的代码验证一下。

所以,环境变量可以被子进程继承!环境变量是 "父传子、子传孙" 的链式继承关系,每一层子进程都会复制上一层父进程的环境变量,因此可以一直传递下去。所以环境变量在系统当中通常具有全局特性。
虽然变量会层层继承,但每个进程的环境变量都是独立副本,互不影响:

  • 你在子进程 B 里修改 / 删除 MY_VAR,只会影响 B 和它的子进程 C,不会回传给父进程 A
  • 这是典型的 ** 写时复制(Copy-on-Write)** 机制,父进程和子进程的环境变量是完全独立的。

方法二:getenv,根据环境变量的名字来获取环境变量的内容, 找到就返回值的字符串指针 ,找不到返回 NULL

一个有意思的问题,如何使用 getenv 设计一个程序,只能我执行,其他人一律不执行?使用USER!

重新登录一个账号root,发现即使是root也不可以执行该程序正常的执行逻辑

方法三:通过第三⽅变量environ获取

environLinux C 语言的全局变量 ,它直接指向当前进程的整个环境变量表 。它就是 main 函数第三个参数 env [] 的真身

每个程序都会收到⼀张环境表,环境表是⼀个字符指针数组,每个指针指向⼀个以'\0'结尾的环境 字符串

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

程序运行结果:

推荐第二种,获取具体某一个环境变量 getenv


5、理解环境变量的特性

5.1 环境变量具有全局特性(见上)

5.2 补充两个概念(给后面埋一个伏笔)

a、本地变量

i=10,是设置一个本地变量的操作

为什么 echo $i 能看到,但 env 看不到?

  • 你定义的 i=10 是「局部变量」

    • 直接赋值 i=10(等号两边不能有空格),创建的是 Shell 局部变量
    • 局部变量只存在于当前 Shell 进程内部,只能用 echo $变量名 查看
    • env 命令默认只显示环境变量,所以看不到它
  • env 看不到的根本原因:它没被放进「环境变量表」

    • 只有用 export 导出的变量,才会被写入当前 Shell 的环境变量表
    • env 命令读取的,正是这张表,所以 export 过的变量才会被列出来
  • set:显示环境变量和本地变量

关于本地变量

  • bash会记录两套变量:1、环境变量,2、本地变量
  • 本地变量不会被子进程继承,只会在bash内部被使用!
  • 本地变量就是当前 Shell 的 "私有临时变量",适合做临时数据暂存、脚本内逻辑控制,轻量又安全,不会污染全局环境和子进程。

export 变量名,是已存在的本地变量 ,升级为环境变量,供子进程继承。

b、首先我们要知道:我们的环境变量是在谁里面?bash!

所以,有个问题:export 会将环境变量导入到父进程 Bash 中,但如果 export 是作为子进程执行的,那么按照进程独立性原则,子进程的修改不应该影响父进程,但实际上 export 确实改变了 Bash 的环境变量,这是为什么呢?

因为export是一个内建命令built-in command,内建命令--->不需要创建子进程,而是让bash亲自执行,bash自己调用函数,或者系统调用完成。pwd 也是 Bash 内建命令,只要当前 Bash 进程正常运行,就能执行 pwd 命令获取当前工作目录,不依赖外部可执行文件。

结束,现在再回看一下环境变量的概念就会好理解一点。

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

完------


至此结束------

我是云边有个稻草人

期待与你的下一次相遇!

相关推荐
IMPYLH2 小时前
Linux 的 stdbuf 命令
linux·运维·服务器·bash
郝学胜-神的一滴2 小时前
从底层看透Linux高性能服务器:epoll自定义封装与超时清理实战
linux·服务器·c++·网络协议·tcp/ip·unix
keyipatience2 小时前
12.GDB调试技巧与计算机体系结构解析
linux·运维·服务器
小夏子_riotous2 小时前
Docker学习路径——9、Docker 网络深度解析:从默认网络到自定义网络实战
linux·运维·网络·docker·容器·centos·云计算
峥无2 小时前
《read/write的秘密:文件描述符、重定向与用户态缓冲区》
linux·运维·服务器·进程
fish_xk2 小时前
Linux操作系统
linux
zh路西法2 小时前
【udev重命名详细教程】放弃硬编码,从重命名开始
linux·机器人
studytosky2 小时前
【高并发内存池】线程缓存核心原理与实现
linux·服务器·git·缓存
lihao lihao2 小时前
Linux文件与fd
java·linux·算法