Linux 上的环境变量及生效范围
前言
在 Linux 中,环境变量可按「作用范围」从大到小分为四类:
| 层级 | 典型位置 | 简要说明 |
|---|---|---|
| 系统级 | /etc/environment、/etc/profile、/etc/profile.d/ |
所有用户登录时加载;systemd/cron/init.d 默认不读 |
| 用户级 | ~/.bashrc、~/.bash_profile、~/.profile、~/.pam_environment |
仅当前用户,登录或交互式 shell 时加载 |
| 会话级 | 当前 Shell 中 export、source |
仅当前终端会话及子进程 |
| 进程级 | 命令行 VAR=value command 或 env VAR=value command |
仅该命令及其子进程 |
要点速记:
- 系统级:
/etc/environment仅 PAM 登录会话生效,不支持$VAR引用;/etc/profile与/etc/profile.d/*.sh在登录 shell 时执行,非登录 shell 不加载。 - 用户级:
~/.bashrc在交互式非登录 shell 加载(新开终端);登录 shell 需在~/.bash_profile或~/.profile里source ~/.bashrc才会带上。 - 服务/脚本:systemd 服务、cron、init.d 脚本不会自动读上述文件,需在服务配置或脚本里显式加载或使用
EnvironmentFile。
配置位置对比
| 位置 | 适用场景 | 说明 |
|---|---|---|
~/.bashrc |
当前用户、交互式 shell | 新开终端时加载;登录 shell 需在 ~/.bash_profile 里 source |
~/.profile |
当前用户、登录 shell | 图形/SSH 登录时生效;dash 等非 bash 也读 |
~/.bash_profile |
当前用户、bash 登录 shell | 查找顺序:~/.bash_profile → ~/.bash_login → ~/.profile,找到即停 |
/etc/environment |
全局(所有用户) | 仅 KEY=value,不支持 $VAR 与 shell 语法;PAM 登录才生效 |
/etc/profile、/etc/profile.d/*.sh |
全局、登录 shell | 系统级配置,需 root;推荐用 profile.d 便于维护 |
命令行 export |
当前会话 | 仅当前终端,关闭即失效,适合调试 |
/etc/environment 详解
/etc/environment 是系统级配置,特点如下:
- 格式:仅支持
KEY=value,不能写 shell 语法或变量引用(如$PATH)。 - 加载时机:由 PAM 在用户登录时读取,不是 shell 脚本,不能
source。 - 生效范围:仅对 PAM 登录会话生效,init.d 脚本、systemd 服务、cron 不会读,因此不适合给服务用。
编辑与示例:
1 | sudo vi /etc/environment |
内容示例(纯键值对):
1 | JAVA_HOME="/usr/local/jdk/bisheng-jdk1.8.0_422" |
生效方式:重新登录 SSH 或重启;若需当前终端立刻生效,只能在本终端手动 export,例如:
1 | export JAVA_HOME="/usr/local/jdk/bisheng-jdk1.8.0_422" |
服务中环境变量生效
/etc/profile 只在用户登录 shell 时被读取;init.d 脚本由 systemd/init 在系统级直接执行,不经过登录 shell,因此读不到 /etc/profile 里的变量。
做法:在 init.d 脚本开头用 . /etc/profile 或 source /etc/profile 显式加载。
init.d 脚本示例:
1 |
|
常见场景
选择哪个位置主要取决于以下三个因素:
- 作用范围:是全局生效(所有用户/服务)还是仅当前用户/应用生效?
- 服务启动方式:是通过 systemd 服务启动,还是手动命令行启动?
- 安全性:是否包含敏感信息(如密码、密钥)?
以下是针对不同场景的最佳实践建议:
部署应用程序
适用情况:Java、Python、Node.js、Go 等后端服务,尤其是由 systemd 管理的服务。
最佳位置:应用专属的 .env 文件 或 systemd 服务配置文件。
理由:
- 隔离性:变量只对该应用生效,不会污染系统环境。
- 安全性:可以将文件权限设置为
600(仅所有者可读),避免其他用户窃取密钥。 - 兼容性:解决了
systemd不加载~/.bashrc导致变量失效的经典问题。
操作方法:
方法 A (Systemd 推荐):
编辑服务单元 /etc/systemd/system/your-app.service:
1 | [Service] |
保存后执行:
1 | sudo systemctl daemon-reload |
方法 B (代码加载):
在代码中使用库(如 Python 的 python-dotenv 或 Node.js 的 dotenv)读取项目根目录下的 .env 文件。
全局系统配置(所有用户生效)
适用情况:安装 JDK, Maven, Go 等开发工具,需要所有用户都能使用命令。
最佳位置:/etc/profile.d/*.sh (Linux 通用推荐)
理由:
- 模块化:在
/etc/profile.d/下单独建脚本(如java.sh),比直接改/etc/profile更清晰,系统升级时也不易被覆盖。 - 语法支持:支持完整的 Shell 脚本语法(如
export VAR=$VAR:/new/path),而/etc/environment不支持变量引用。
操作方法:
1 | sudo vim /etc/profile.d/my_custom_vars.sh |
内容示例:
1 | export JAVA_HOME=/usr/lib/jvm/java-11 |
保存后,新登录的用户会自动生效,或执行:
1 | source /etc/profile |
注意:需要追加路径(如 PATH=$PATH:xxx)时不要用 /etc/environment,它不支持变量引用,只支持纯 KEY=value。
仅当前用户生效(交互式终端)
适用情况:个人开发账号,设置别名、提示符或仅在终端操作时需要的变量。
最佳位置:~/.bashrc (CentOS/Ubuntu 默认) 或 ~/.zshrc (如果使用 Zsh)。
理由:不影响其他用户,每次打开新终端窗口自动加载。
缺点:如果是通过 systemd 启动的服务,在这里设置的变量通常无效,因为服务进程不经过交互式 Shell 登录。
操作方法:
1 | echo 'export MY_VAR="hello"' >> ~/.bashrc |
注意:修改后记得执行 source ~/.bashrc 或重新打开终端窗口。
包含高度敏感信息(数据库密码、API 密钥等)
最佳位置:云厂商密钥管理(如 KMS/ACM)或权限严格的 .env 文件。
不要把明文密码写在 /etc/profile 或 ~/.bashrc 中:这些文件多为 644,同机其他用户可读,存在泄露风险。
推荐做法:
- 将敏感项放在单独
.env,并执行chmod 600 .env(仅所有者可读)。 - 在 systemd 的
[Service]里用EnvironmentFile=/path/to/.env引入;不要用全局 profile。
总结对比表
| 配置文件/位置 | 作用范围 | Systemd 服务 | 变量引用 $VAR |
推荐用途 |
|---|---|---|---|---|
/etc/systemd/system/*.service(EnvironmentFile) |
指定服务 | ✅ 推荐 | ✅ | 生产应用部署(首选) |
/etc/profile.d/*.sh |
全局 | ❌ 不加载 | ✅ | 全局工具(JDK、Maven 等) |
~/.bashrc |
当前用户、交互式 | ❌ 不生效 | ✅ | 个人别名、开发习惯 |
/etc/environment |
全局 | ❌ 不加载 | ❌ | 简单静态全局变量 |
项目 .env |
当前应用 | ⚠️ 需代码或 EnvironmentFile | ✅ | 多环境配置(Dev/Prod) |
常见问题
1. 在 ~/.bashrc 里加了变量,重启服务后没生效?
systemd 启动服务时不会启动登录/交互式 Shell,因此不会读 .bashrc。应改为在 unit 里用 EnvironmentFile 或 Environment= 指定变量(推荐 EnvironmentFile)。
2. CentOS 和 Ubuntu 有区别吗?
逻辑一致。Ubuntu 可能更多用 /etc/environment 做极简配置,但若需要变量展开和脚本能力,两者都推荐用 /etc/profile.d/*.sh 做全局配置。
3. 修改后如何立即生效?
- 用户级:
source ~/.bashrc或新开终端。 - 全局级:
source /etc/profile或重新 SSH 登录。 - 服务级:
sudo systemctl daemon-reload && sudo systemctl restart <服务名>。
结论
- 跑业务服务:用 systemd 的
EnvironmentFile指向权限严格的.env。 - 装全局开发工具:用
/etc/profile.d/custom.sh。 - 仅自己终端用:用
~/.bashrc(或~/.zshrc)。