惯性聚合 高效追踪和阅读你感兴趣的博客、新闻、科技资讯
阅读原文 在惯性聚合中打开

推荐订阅源

Google Online Security Blog
Google Online Security Blog
S
Security @ Cisco Blogs
Recent Commits to openclaw:main
Recent Commits to openclaw:main
人人都是产品经理
人人都是产品经理
The Hacker News
The Hacker News
W
WeLiveSecurity
freeCodeCamp Programming Tutorials: Python, JavaScript, Git & More
OSCHINA 社区最新新闻
OSCHINA 社区最新新闻
The Cloudflare Blog
博客园 - 司徒正美
雷峰网
雷峰网
L
LINUX DO - 最新话题
博客园 - 叶小钗
云风的 BLOG
云风的 BLOG
The Last Watchdog
The Last Watchdog
V2EX - 技术
V2EX - 技术
S
Security Affairs
有赞技术团队
有赞技术团队
月光博客
月光博客
T
Threatpost
T
Tor Project blog
O
OpenAI News
cs.AI updates on arXiv.org
cs.AI updates on arXiv.org
cs.CL updates on arXiv.org
cs.CL updates on arXiv.org
V
V2EX
Know Your Adversary
Know Your Adversary
Project Zero
Project Zero
博客园 - 三生石上(FineUI控件)
D
Docker
AWS News Blog
AWS News Blog
AI
AI
P
Proofpoint News Feed
K
Kaspersky official blog
H
Hackread – Cybersecurity News, Data Breaches, AI and More
D
Darknet – Hacking Tools, Hacker News & Cyber Security
www.infosecurity-magazine.com
www.infosecurity-magazine.com
S
Securelist
F
Fortinet All Blogs
F
Full Disclosure
cs.CV updates on arXiv.org
cs.CV updates on arXiv.org
量子位
Hacker News - Newest:
Hacker News - Newest: "LLM"
CTFtime.org: upcoming CTF events
CTFtime.org: upcoming CTF events
P
Palo Alto Networks Blog
Cyberwarzone
Cyberwarzone
Cisco Talos Blog
Cisco Talos Blog
美团技术团队
N
News | PayPal Newsroom
T
The Blog of Author Tim Ferriss
MyScale Blog
MyScale Blog

f2h2h1's blog

使用yii3实现一个微框架 claw养殖技术 计算机网络基础知识 定时任务 ACME的使用经验 magento2加上varnish缓存 开发Magento2的模块 在magento2中使用persisted-query socket编程 一些开发笔记 一段CSDN文章主要内容的油猴脚本 电子邮件的不完整总结 git的笔记 在Windows下配置PHP服务器 终端,控制台和外壳 PHP各种运行方式的不完整总结 把网页导出成PDF 和颜色相关的笔记 HTTP认证方式的不完整总结 SEO的经验 密码学入门简明指南 文件的上传和下载 用纯CSS3实现的滑动按钮 在VSCode里调试PHP Linux的GUI 关于字符编码的一些坑 nc的使用和原理 在Windows下安装Magento2 对JS原型链的理解 使用docker-compose部署magento2 浏览器和服务器通讯方式的不完整总结 观察网站性能 一些关于Linux的笔记 telnet的不完整总结 在Windows下安装pear MySQL的时间类型和时间相关的函数 Windows下通过PEB读取进程的环境变量 关于 在VSCode里使用Xdebug远程调试PHP 在Windows下搭建git服务 使用shell实现的kv数据库 如何完成以xx管理系统为选题的毕业设计 数字号码资源 各种标记语言 使用PowerShell实现的http服务器 kind相关经验 DNSSEC简介 nginx+ffmpeg+websocket实现的直播例子 使用Tesseract识别字符验证码 使用docker部署nuxt FirstData后台的设置 paypal,firtdata,支付宝的不完整接入指南 微信支付的不完整接入指南 用docker-compose部署lnmp环境 mongodb分片 练习
关于环境变量的不完整总结
2023-09-19 · via f2h2h1's blog

关于环境变量的不完整总结

这篇文章最后更新的时间在六个月之前,文章所叙述的内容可能已经失效,请谨慎参考!

环境变量是什么

环境变量(environment variables)

  • 现代操作系统都有环境变量
  • 环境变量是键值对
  • 环境变量的 键 值 都是字符串
  • 程序可以通过系统 API 访问环境变量
  • 环境变量 最早出现在 Version 7 Unix ,然后后续的操作系统都继承了这样的设计
  • 环境变量是进程运行环境的一部分
    • 例如,正在运行的进程可以查询 TEMP 环境变量的值以发现存储临时文件的合适位置,
    • 或者查询 HOME 或 USERPROFILE 变量的值以查找运行该进程的用户所拥有的目录结构。
  • 每个进程都有自己单独的环境变量
  • 环境变量可以修改,但一般只能在当前进程或子进程生效
  • 环境变量由父进程设置
    • 默认情况下会复制父进程的环境变量
    • 父进程也可以单独地设置子进程的环境变量
  • 环境变量的作用
    • 让进程知道当前的运行环境
    • 把数据传递给子进程
    • 存储临时数据
  • 环境变量的作用域
    • 当前进程
      • 当前终端的环境变量实质上就是当前 shell 的环境变量,也是进程的作用域
    • 当前用户
    • 全局
  • 常见的环境变量
    • PATH: 列出 shell 搜索 用户 输入的执行命令所在的目录。
    • HOME: (类Unix系统) 和 userprofile (Microsoft Windows) 表示用户的家目录在文件系统中的位置。
    • TEMP: 进程可以存储临时文件的位置。
    • JAVA_HOME: jdk 目录的路径
  • 伪环境变量 pseudo environment variables
    • 并不真正存储在环境中,而是在请求时计算的
    • 例如 cmd 里的 %CD% %DATE% , bash 里的 $RANDOM
    • 伪环境变量好像只能在 shell 里使用,笔者虽然没有找到更多的资料,但实践的结果确实是这样
      • powershell 里没有 cmd 里的伪环境变量,猜测是使用cmd-let替代了

在 Unix 系统通过初始化脚本启动时,环境变量通常会在此时被初始化,因此会被系统中的其它进程所继承。

在 Windows 系统中,环境变量存储在 Windows 注册表中。

  • 环境变量保存在这几个位置,大多数情况下只需要修改 CurrentControlSet 就可以了
    • HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Control\Session Manager\Environment
    • HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Control\Session Manager\Volatile Environment
    • HKEY_LOCAL_MACHINE\SYSTEM\ControlSet001\Control\Session Manager\Environment
    • HKEY_LOCAL_MACHINE\SYSTEM\ControlSet001\Control\Session Manager\Volatile Environment
    • HKEY_LOCAL_MACHINE\SYSTEM\ControlSet002\Control\Session Manager\Environment
    • HKEY_LOCAL_MACHINE\SYSTEM\ControlSet002\Control\Session Manager\Volatile Environment
    • HKEY_USERS\用户的sid\Environment
    • HKEY_USERS\用户的sid\Volatile Environment
  • 大多数情况下关注 Environment 就可以了
  • Volatile Environment 是一些和用户相关的变量,会跟随用户改变而改变,例如 userprofile
  • 对于环境变量而言,注册表中有两种类型
    • REG_SZ
    • REG_EXPAND_SZ
    • 具体区别是
      • REG_SZ 类型的键值中存在的可扩展占位符 %xxx% 不会被系统解释;
      • REG_EXPAND_SZ 类型的键值中存在的 %xxx% 的部分会被系统解释。
    • 好像是只要用户新建或修改过的环境变量,类型都会是 REG_EXPAND_SZ
  • 可以通过直接读写注册表里的值来修改环境变量 (可能会因为权限不足而失败)

在 cmd 里操作环境变量

  1. 查看全部环境变量
    set
    
  2. 设置环境变量
    set example=testvar
    
  3. 输出环境变量
    echo %path%
    
    • 访问环境变量和访问普通变量是一样的
    • 环境变量名大小写不敏感
  4. 删除环境变量
    set example=
    
  5. 修改环境变量
    • 可以直接覆盖原本的环境变量
    • 可以先删除再新建
  6. 给 path 添加新的路径
    set path=%path%;C:\Tools
    

cmd 里修改环境变量只影响当前的进程

在 powershell 里操作环境变量

PowerShell 提供了几种不同的方法来使用和管理环境变量

  • 使用 variable 语法
  • cmdlet
  • .NET 类

使用 variable 语法

  1. 查看全部环境变量
    ls Env:
    
  2. 设置环境变量
    $Env:example = "testvar"
    
  3. 输出环境变量
    echo $Env:example
    
    • 访问环境变量和访问普通变量是一样的
    • 环境变量名大小写不敏感
  4. 删除环境变量
    del Env:example
    
  5. 修改环境变量
    • 可以直接覆盖原本的环境变量
    • 可以先删除再新建
  6. 给 path 添加新的路径
    $Env:Path += ';C:\Tools'
    

cmdlet

  1. 查看全部环境变量
    Get-Item -Path Env:\*
    
  2. 设置环境变量
    New-Item -Path Env: -Name example -Value 'testvar'
    或
    Set-Item -Path Env:example -Value 'testvar'
    
  3. 输出环境变量
    Get-Item -Path Env:\example
    Get-Item -Path Env:\example | Select-Object -Property Value
    Get-Item -Path Env:\example | Select-Object -ExpandProperty Value
    
  4. 删除环境变量
    Remove-Item -Path Env:example
    
  5. 修改环境变量
    修改值
    Set-Item -Path Env:example -Value 'testvar2'
    重命名
    Rename-Item -Path Env:example -NewName example
    
  6. 给 path 添加新的路径
    Set-Item -Path Env:\Path -Value $Env:Path';C:\Tools'
    Set-Item -Path Env:\Path -Value ((Get-Item -Path Env:\Path | Select-Object -ExpandProperty Value)+';C:\Tools')
    

.NET 类

  1. 查看全部环境变量
    [Environment]::GetEnvironmentVariables()
    
  2. 设置环境变量
    [Environment]::SetEnvironmentVariable('example', 'testvar')
    
  3. 输出环境变量
    [Environment]::GetEnvironmentVariable('example')
    
  4. 删除环境变量
    [Environment]::SetEnvironmentVariable('example', '')
    
  5. 修改环境变量
    • 可以直接覆盖原本的环境变量
    • 可以先删除再新建
  6. 给 path 添加新的路径
    [Environment]::SetEnvironmentVariable('path', [Environment]::GetEnvironmentVariable('path') + ';C:\Tools')
    

保存环境变量的修改

Environment 能修改全局的或当前用户的环境变量,其它两种方法在默认情况下都是修改当前进程的环境变量。修改全局的环境变量可能会遇到权限的问题。

[Environment]::SetEnvironmentVariable('example', 'testvar', [EnvironmentVariableTarget]::Process)
[Environment]::SetEnvironmentVariable('example', 'testvar', [EnvironmentVariableTarget]::User)
[Environment]::SetEnvironmentVariable('example', 'testvar', [EnvironmentVariableTarget]::Machine)

在 windows 修改环境变量最保险的方式还是通过这里修改

此电脑 -> 属性 -> 高级系统设置 -> 环境变量

使用 wmic 操作环境变量

  1. 查看全部环境变量

    wmic ENVIRONMENT
    wmic ENVIRONMENT where "username='<system>'"
    
  2. 设置环境变量

    wmic ENVIRONMENT create name="JAVA_HOME",username="<system>",VariableValue="%javaPath%"
    
  3. 输出环境变量

    wmic ENVIRONMENT where "name='Path' and username='<system>'"
    
  4. 删除环境变量

    wmic ENVIRONMENT where "name='JAVA_HOME' and username='<system>'" delete
    

使用 wmic 修改环境变量时要注意作用域,如果没有指定 username ,可能会把所有用户和系统全局的环境变量一起修改。

其实 windows 里还有很多奇技淫巧可以修改环境变量

在 bash 里操作环境变量

  1. 查看全部环境变量
    printenv
    或
    export -p
    
  2. 设置环境变量
    export example=testvar
    
  3. 输出环境变量
    echo $PATH
    或
    printenv PATH
    
    • 访问环境变量和访问普通变量是一样的
    • 环境变量名大小写敏感
  4. 删除环境变量
    export -n example
    
  5. 修改环境变量
    • 可以直接覆盖原本的环境变量
    • 可以先删除再新建
  6. 给 path 添加新的路径
    export PATH=$PATH:/usr/local/nginx/sbin
    
    • 在 Linux 或 macOS 上,使用冒号 (:) 而不是分号 (;)

保存环境变量的修改

  • bash 修改的环境变量只在当前 shell 有效, shell 关闭后就会失效
  • 修改用户的环境变量
    1. 修改这个文件
      ~/.bashrc
      
    2. 修改环境变量时,大致需要这样修改,因为是脚本文件所以就是在脚本里添加 export 命令来修改环境变量
      # 添加一个新的环境变量
      export example=testvar
      # 给 path 添加新的路径
      export PATH=$PATH:/usr/local/nginx/sbin
      
    3. 修改 ~/.bashrc 后,运行这句命令就能生效
      source ~/.bashrc
      
  • 修改系统的环境变量
    1. 修改这个文件
      /etc/bashrc (redhat)
      /etc/bash.bashrc (debian)
      
    2. 又或者直接修改这个文件 /etc/environment
      • /etc/environment 是纯文本文件,不是脚本,不能用变量
      • /etc/bash.bashrc , /etc/profile 这类是 shell 脚本
    3. 修改系统的环境变量则需要重启系统才能生效
    4. 修改这个文件 /etc/profile 也可以达到类似的效果
      • /etc/profile 是用户登录时执行的脚本
      • (但这里其实是有一点坑的,因为有些 shell 脚本执行时可能不需要登录用户)
  • liunx 环境变量的修改本质上是修改各种配置脚本
    • 各种配置脚本有不一样的加载顺序 (可以参考这篇文章《终端,控制台和外壳》)
    • 各种配置脚本在不同的发行版里可能会有不同的文件名
    • source 命令的作用是在当前 shell 中执行脚本,不会启动新的 shell
    • export 命令的作用是设置或显示环境变量, export 可新增,修改或删除环境变量,供后续执行的程序使用

在 c 语言里操作环境变量

c 里有一系列的函数来操作环境变量

char *getenv(const char *name);
int putenv(char *string);
int setenv(const char *envname, const char *envval, int overwrite);
int unsetenv(const char *name);
char *secure_getenv(const char *name);
int clearenv(void);
  • 这些函数都在在头文件 stdlib.h 中声明
  • 全局变量 char **environ 和 main 函数的第三个参数 char* envp[] 都保存有完整的环境变量
    • 全局变量 char **environ 在头文件 unistd.h 中声明
  • 只有 getenv 是 ascii c
  • putenv, setenv, unsetenv 这三个函数和 environ envp 都是来自 posix
  • secure_getenv 和 clearenv 来自 gun c
  • 笔者其实没多少心思区分哪个函数来自哪个标准,反正用 gcc 编译时都能用。

例子

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

    for (char **var = environ; *var != NULL; ++var)
    {
        printf("%s\n", *var);
    }
    printf("****\n");
    
    printf("%s\n", getenv("PATH"));
    printf("****\n");
    
    putenv("TEST=123");
    printf("%s\n", getenv("TEST"));
    printf("****\n");

    int overwrite = 1;
    setenv("TEST", "321", overwrite);
    printf("%s\n", getenv("TEST"));
    printf("****\n");
    
    unsetenv("TEST");

    clearenv();

    return 0;
}

其它语言操作环境变量也会有相应的语法,只要看一下文档就好了。

查看某个进程的环境变量

参考