Shell脚本如何设置环境变量:从入门到精通的全方位指南
📚 目录导读
环境变量基础概念
1 什么是环境变量?
环境变量是操作系统中存储动态配置信息的键值对(Key-Value Pair),它们影响程序运行时的行为,例如PATH变量决定了系统在哪些目录查找可执行文件,在Shell脚本中正确设置环境变量,是自动化部署、配置管理和开发环境隔离的关键技能。

2 为什么需要脚本化设置?
- 避免手动重复操作:每次登录都要手动
export变量显然不现实。 - 环境一致性:通过脚本统一为开发、测试、生产环境注入相同变量。
- 动态配置:根据脚本参数或系统状态(如主机名、时间戳)生成变量值。
核心问题:Shell脚本中设置的变量是否永久生效?答案是否定的——除非通过特定文件持久化。
Shell脚本中设置环境变量的核心方法
1 临时设置:export命令
#!/bin/bash export MY_VAR="hello" echo $MY_VAR # 输出 hello
- 作用域:仅在当前Shell及由当前Shell启动的子进程中生效,脚本结束后变量消失。
- 注意:如果直接在终端执行脚本(如
./script.sh),脚本运行在子Shell中,变量不会影响父Shell。
2 使用source或执行脚本
source ./set_env.sh # 或 . ./set_env.sh
- 核心区别:
source在当前Shell进程中执行脚本,因此变量会立即注入当前环境。 - 场景:通常用于加载配置文件(如
.bashrc),或在自动化流水线中临时激活环境。
3 同时设置多个变量
export APP_HOME="/opt/app" DB_URL="mysql://localhost:3306/db"
最佳实践:对于多变量,使用换行提高可读性:
export APP_HOME="/opt/app" export DB_URL="mysql://localhost:3306/db" export LOG_LEVEL="INFO"
4 在脚本内输出环境变量供子进程使用
# 脚本 run.sh #!/bin/bash export MESSAGE="Hello from parent" ./child.sh # child.sh 能读取到 $MESSAGE
永久性环境变量配置实战
1 全局配置文件(影响所有用户)
/etc/environment:系统级,非脚本语法,使用key=value格式。/etc/profile:登录时执行,支持Shell语法。/etc/bash.bashrc(Debian系)或/etc/bashrc(RedHat系):非登录交互Shell加载。
示例:在/etc/profile中添加:
export JAVA_HOME="/usr/lib/jvm/java-11-openjdk-amd64" export PATH="$JAVA_HOME/bin:$PATH"
2 用户级配置文件(仅当前用户)
~/.bashrc:每次打开新终端时(交互式非登录Shell)执行。~/.bash_profile或~/.profile:登录Shell时执行(Linux/Mac)。
添加永久变量:
echo 'export MY_TOOL_PATH="/home/$USER/my_tools"' >> ~/.bashrc source ~/.bashrc # 立即生效
3 Systemd服务环境变量(适用于系统服务)
在服务单元文件中使用Environment=指令:
[Service] Environment=MY_VAR=123 Environment=ANOTHER_VAR=abc
作用域与子进程继承问题解析
1 父子Shell继承规则
| 场景 | 变量是否被子进程继承 | 示例 |
|---|---|---|
| 普通变量(未export) | VAR=1,子进程看不到 |
|
| export后变量 | export VAR=1,子进程可读 |
|
| source加载 | 在当前Shell中生效 |
2 子Shell不继承修改
# 在父Shell export VAR="parent" bash -c 'echo $VAR' # 输出 parent? 是的 export VAR="child_only" bash -c 'echo $VAR' # 输出 child_only? 依然输出 parent,因为子Shell复制了变量副本
陷阱:子进程对变量的修改不会传回父进程。
3 使用env命令查看/传递环境
env # 打印所有环境变量 env -i my_cmd # 清空环境后执行 env MY_VAR=test my_cmd # 临时注入单个变量
高级技巧:动态变量与安全考量
1 根据参数动态设置
#!/bin/bash
case "$1" in
dev)
export DB_HOST="localhost"
;;
prod)
export DB_HOST="10.0.1.100"
;;
esac
2 读取文件注入变量
使用source加载环境文件(.env格式):
# config.env MY_KEY="abc123" MY_SECRET="s3cr3t" # 脚本中 source config.env
3 安全告警:永远不要硬编码密码
# ❌ 危险做法 export DB_PASSWORD="mypassword123" # ✅ 推荐:从密钥管理服务或加密文件读取 export DB_PASSWORD=$(cat /run/secrets/db_password)
4 变量默认值与校验
# 若未设置则使用默认值
export JAVA_HOME="${JAVA_HOME:-/usr/lib/jvm/default-java}"
# 确保变量不为空
if [ -z "$JAVA_HOME" ]; then
echo "ERROR: JAVA_HOME is not set" >&2
exit 1
fi
5 使用eval动态构造变量名(谨慎使用)
prefix="MY_APP"
eval export ${prefix}_HOME="/opt/app"
echo $MY_APP_HOME # 输出 /opt/app
常见错误与故障排除
1 问题1:脚本设置后当前终端看不到变量
原因:直接运行./script.sh而非source。
解决:使用source script.sh或. script.sh。
2 问题2:变量在子脚本中不生效
检查点:是否使用了export?子脚本是否是同一个Shell?
方案:在子脚本开头重新source配置文件,或所有关联脚本均通过source运行。
3 问题3:sudo下环境变量丢失
原因:sudo默认清理环境变量。
解决:
- 保留变量:
sudo -E ./your_script.sh - 在
/etc/sudoers中设置env_keep。
4 问题4:变量值含空格或特殊字符
# 错误写法(引号缺失) export PATH=/opt/my app/bin:$PATH # 路径含空格会解析为两个参数 # 正确写法 export PATH="/opt/my app/bin:$PATH"
5 问题5:环境变量在图形界面应用不生效
原因:GUI应用通常从~/.pam_environment或启动器中读取环境。
解决:将变量放入~/.bashrc并确保桌面会话加载了该文件,或使用/etc/environment。
问答精选(FAQ)
Q1: 在Shell脚本中设置的环境变量,为什么退出脚本后又消失了?
A: 因为默认方式下,脚本运行在子Shell中,当脚本退出,子Shell销毁,其中定义的变量也随之消失,想让变量影响当前终端,必须使用source或执行脚本。
Q2: export和直接赋值有什么区别?
A: 直接赋值(如VAR=value)的变量只属于当前Shell,不会被子进程继承。export标记该变量应传递给所有后续启动的子进程,可以理解为export赋予了变量“可遗传”的特性。
Q3: 如何区分“登录Shell”和“非登录Shell”的配置文件加载顺序?
A:
- 登录Shell:执行顺序:
/etc/profile→~/.bash_profile(或~/.bash_login、~/.profile)。 - 非登录交互Shell:仅执行
~/.bashrc(通常系统也会加载/etc/bash.bashrc)。
永久环境变量通常放在~/.bashrc(对所有终端生效)或~/.profile(仅登录时)。
Q4: 设置PATH时,为什么总有人写export PATH="/new/path:$PATH"而不是export PATH="$PATH:/new/path"?
A: 变量展开顺序决定优先级。前置意味着新路径优先于系统原有路径,例如若/new/path中含有与系统命令同名的可执行文件,会优先执行新目录中的版本。后置则降低优先级,通常将用户自定义路径前置。
Q5: 在Docker容器中设置环境变量有什么特殊注意事项?
A: Docker中可通过ENV指令(Dockerfile)、-e参数(docker run)或env_file方式设置,Shell脚本中直接使用export无效(除非在ENTRYPOINT脚本中),注意多阶段构建中,前一阶段的变量不会自动带到下一阶段,需重新声明。
Q6: 如何安全地删除一个环境变量?
A: 使用unset命令:
unset MY_VAR # 仅删除当前Shell中的该变量
若要从配置文件中删除永久变量,需手动编辑文件并移除对应的export行,然后重新加载。
Q7: 脚本中设置环境变量后,还需要source才能让后续命令使用吗?
A: 如果脚本本身被source执行(而不是作为子进程),那么脚本结束后,其设置的所有export变量会保留在当前Shell中,后续命令可以直接使用,但如果脚本是直接运行(./script.sh),则不会,因为那是子Shell的上下文。
通过本文的深入解析,你应该已经掌握了从临时设置到永久持久化、从基础功能到高级动态配置的完整技能树,记住一个核心原则:环境变量的生命周期取决于它被定义的位置和方式,合理运用export、source及系统配置文件,就能在任何Unix/Linux环境中优雅地掌控变量注入。
最后一道自测题:echo 'export FOO=bar' | bash 这段代码会让当前Shell获得FOO变量吗?答案:不会,因为管道符右侧的bash是一个子Shell,变量不会传递回父进程。