怎么用脚本设置临时环境变量(Shell/Python/Bat全攻略)
📚 目录导读
- 为什么需要临时环境变量?
- 基础概念:临时环境变量 vs 永久环境变量
- Shell脚本(Linux/macOS)中设置临时环境变量
- 单条命令临时设定
- 多条命令内的变量传递
- 子shell与父shell的隔离机制
- 实战:export、source、exec的区别
- 批处理脚本(Windows CMD/PowerShell)中设置临时环境变量
- CMD下的set与setx
- PowerShell的$env: 与 [Environment]::SetEnvironmentVariable
- 跨脚本传递变量的技巧
- Python脚本中临时设置环境变量
- os.environ字典的临时修改
- subprocess继承环境变量的控制
- dotenv库读取.env文件
- 常见错误与调试方法
- 为什么变量设置后不起作用?
- 查看当前所有环境变量的命令
- QA问答精选(真实场景)
- 选择最佳实践
为什么需要临时环境变量?
在日常开发、CI/CD流水线、或服务器部署时,我们经常需要临时改变程序的行为——比如切换数据库连接字符串、指定日志级别、或者在不影响全局配置的前提下测试新版本API密钥。

典型场景:
- 本地调试时,临时覆盖
DATABASE_URL指向测试库 - 部署脚本中,为单个命令注入密钥而不写入磁盘
- 在多项目并行时,防止环境变量污染全局
~/.bashrc
核心痛点:很多新手在脚本里 export 一个变量后,发现退出脚本就没了,或者发到另一台机器就失效了——这正是“临时”的精髓,我们将从原理到实战,彻底打通。
基础概念:临时环境变量 vs 永久环境变量
| 特性 | 临时环境变量 | 永久环境变量 |
|---|---|---|
| 生命周期 | 当前Shell进程或脚本执行期间 | 用户登录会话 / 系统重启后依然存在 |
| 设置位置 | 终端命令行 / 脚本内 export |
~/.bashrc、/etc/profile、系统属性 |
| 影响范围 | 当前进程及其子进程 | 所有新启动的Shell |
| 典型用途 | 一次性构建、测试、敏感信息注入 | 固定路径、默认编辑器、语言编码 |
一句话记忆:临时变量是“用完即走”,永久变量是“常住户口”。
Shell脚本(Linux/macOS)中设置临时环境变量
单条命令临时设定(最常用)
# 在命令前直接赋值,只对该命令生效 DB_HOST=test.example.com npm run migrate # 多个变量可以并列 API_KEY=123 DEBUG=true python app.py
原理:这其实是 bash 的特性——在当前行前面插入变量赋值,它们被当作“入口环境变量”传递给该命令的子进程,命令结束后变量自动消失,适用于仅一次的调用。
多条命令内的变量传递
如果你想在同一个Shell会话里连续使用变量,需要 export:
#!/bin/bash
# 临时设置,仅对当前脚本内后续命令有效
export MY_SECRET="s3cr3t"
echo "当前变量: $MY_SECRET"
python -c "import os; print(os.getenv('MY_SECRET'))"
注意:脚本结束后 MY_SECRET 不在外部Shell中残留,如果你用 . script.sh 或 source script.sh 执行,则变量会留在当前Shell——这正是 source 的“加载”效果。
子shell与父shell的隔离机制
# 在括号内执行,生成一个子shell ( export TMP_DIR="/tmp/mybuild" cd "$TMP_DIR" && make ) # 退出子shell后,TMP_DIR 和 cd 操作均不影响父shell echo "父shell当前目录: $(pwd)"
常见误解:export 后变量会一直存在?错,它只存在于当前Shell以及它启动的子进程,如果你打开一个新终端,它不存在。
export、source、exec的区别
| 命令 | 行为 | 变量是否持久到当前Shell |
|---|---|---|
export VAR=val |
设置变量并标记为可传递给子进程 | ✅ 是的 |
source script.sh |
在当前Shell中逐行执行脚本 | ✅ 脚本内的export在脚本结束后仍然有效 |
./script.sh |
启动一个子Shell执行脚本 | ❌ 变量在子Shell内有效,执行完后消失 |
exec cmd |
用新进程替换当前Shell | ❌ 原Shell消失,变量在新进程中 |
最佳实践:如果你在一个脚本内需要临时变量,直接在脚本里export,然后用 ./script.sh 执行,不会污染环境。
批处理脚本(Windows)中设置临时环境变量
CMD(传统命令行)
@echo off
REM 临时设置,仅对当前CMD窗口有效
set MY_VAR=temporary_value
echo %MY_VAR%
python -c "import os; print(os.getenv('MY_VAR'))"
关键区别:CMD中 set 默认就是临时变量,退出窗口即消失。setx 才是永久写入注册表。
跨文件传递:如果你在 build.bat 里set了一个变量,想让它影响 deploy.bat,需要 call:
REM build.bat set BUILD_NUM=42 call deploy.bat
PowerShell
# 临时设置当前进程的环境变量
$env:MY_SECRET = "temp123"
python -c "import os; print(os.getenv('MY_SECRET'))"
# 仅对一条命令临时设置(类似Linux前缀写法)
$env:DEBUG='true'; npm run test
# 查看当前所有临时环境变量
Get-ChildItem Env: | Format-Table
永久设置要用 [Environment]::SetEnvironmentVariable("MY_VAR", "value", "User"),这与临时机制完全不同。
PowerShell vs CMD:PowerShell的 $env: 前缀比 set 更直观且支持对象操作,推荐在Windows 10+上优先使用。
Python脚本中临时设置环境变量
通过 os.environ 临时修改
import os
# 临时设置,只影响当前Python进程以及后续os.system/subprocess启动的子进程
os.environ['DATABASE_URL'] = 'postgres://test:pass@localhost:5432/dev'
print(os.environ['DATABASE_URL'])
# 启动子进程,会继承上面的变量
os.system('echo $DATABASE_URL') # Linux/macOS
# 或
os.system('echo %DATABASE_URL%') # Windows
重要:os.environ 是对当前进程环境变量的直接操作,不会写入系统或文件,Python退出后消失。
subprocess 的 env 参数(彻底隔离)
import subprocess
import os
# 创建一个全新的环境,不继承当前进程的环境
new_env = {**os.environ, 'MY_SECRET': 'override'}
subprocess.run(['python', 'child.py'], env=new_env)
# 或者只传递自定义变量(丢弃所有系统变量)
subprocess.run(['python', 'child.py'], env={'APP_MODE': 'test'})
典型用途:在CI脚本中,你不想把 $HOME 或密钥泄露给子进程,就可以自定义 env。
使用 python-dotenv 读取 .env 文件
很多项目用 .env 文件管理临时环境变量:
# .env 文件内容(不需要引号,不需要export) DATABASE_URL=postgres://localhost/mydb SECRET_KEY=abc123
Python读取:
from dotenv import load_dotenv
import os
# 加载 .env 到 os.environ(临时)
load_dotenv()
print(os.getenv('DATABASE_URL'))
优势:无需在脚本或命令行里写死敏感信息,适合提交到GitHub(需gitignore!)。
常见错误与调试方法
❌ 错误1:export后为什么脚本外还能看到?
很可能你用了 source script.sh 而不是 ./script.sh。source 是在当前Shell执行的,export 会残留在你的终端里。
❌ 错误2:Windows下set后,新打开的CMD找不到
这是正常的。set 只对当前CMD窗口有效,如果你需要永久设置,用 setx(但那就不是临时了)。
✅ 调试命令
| 系统 | 查看当前所有环境变量 |
|---|---|
| Linux/macOS | env 或 printenv |
| Windows CMD | set |
| Windows PowerShell | Get-ChildItem Env: 或 dir env: |
| Python | import os; print(dict(os.environ)) |
快速检查特定变量:
echo $PATH # Linux echo %PATH% # CMD echo $env:PATH # PowerShell
QA问答精选(真实场景)
Q1:我在Dockerfile里用ENV设置变量,这是临时的还是永久的?
A:Docker的 ENV 指令是永久的——构建时写入镜像层,容器启动后每个进程都能看到,如果你只想在构建期间临时用(比如下载临时密钥),用 ARG 然后结合 --build-arg 传值,构建完成后不保留。
Q2:用脚本设置临时环境变量,如何确保子进程(如npm、python)能继承到?
A:关键是在父Shell中必须export(或使用上一节的前缀法 VAR=value cmd),如果父进程没有export,子进程只能看到未标记的变量(实际上看不到),检测方式:在子进程中打印 os.environ 或 echo $VAR。
Q3:持续集成(CI)中,怎么安全地传递临时密钥?
A:CI平台(如GitHub Actions、GitLab CI)本身提供了「临时环境变量」机制——你在Web界面设置的Secret会被自动注入到每个Job的Shell里,但不会出现在日志中,在脚本中直接用 $API_KEY 即可,CI平台保证安全性,具体做法:在CI设置里定义 API_KEY,然后在 .gitlab-ci.yml 或 action.yml 的 script: 中使用。
Q4:多个脚本需要共享同一个临时变量,如何避免重复export?
A:创建一个 setup_env.sh 文件,里面只包含export命令,然后在每个脚本中 source 它:
# setup_env.sh export BUILD_ID=$(date +%s) export TARGET_STAGE='dev' # 其他脚本中 source ./setup_env.sh echo "当前构建ID: $BUILD_ID"
这样可以避免每个脚本里写重复的变量值,且变量生命周期仅限于脚本执行期间(如果不沿用 source 的话)。
Q5:Windows下用Start-Job启动异步任务,环境变量能传递吗?
A:默认不会,需要在 Start-Job 中显式使用 -ArgumentList 或设置 $env: 在脚本块内,推荐做法:
$job = Start-Job -ScriptBlock { param($port) $env:PORT=$port; node server.js } -ArgumentList 8080
选择最佳实践
| 场景 | 推荐方法 |
|---|---|
| 只运行一次命令(最常见) | VAR=val command(Linux) / $env:VAR='val'; command(PowerShell) |
| 脚本内有多个命令需要共享 | export(Linux) / set(CMD) / $env:(PowerShell) |
| Python内部临时覆盖 | os.environ['KEY']='val' |
| 不希望子进程继承过多变量 | subprocess.run(..., env={}) |
| 管理项目配置文件 | .env + python-dotenv |
| CI/CD流水线中传敏感信息 | CI平台的内置Secret变量 |
最后建议:始终明确“临时”的边界——脚本执行完后,变量应该自动消失,不留痕迹,如果某个变量需要跨会话使用,请把它加入 ~/.bashrc 或系统环境变量,但那就不属于本文讨论的“临时”范畴了。
(全文约2900字)