export 命令仅对当前 shell 及其子进程有效,不持久化;永久生效需写入 ~/.bashrc(交互式非登录 shell)、~/.profile(登录 shell)或系统级配置如 /etc/environment(无变量展开)或 /etc/profile.d/*.sh(支持完整 shell 语法)。

export 命令只对当前 shell 有效
你执行 export PATH="/my/bin:$PATH" 后,新开终端或运行脚本时变量就没了——因为 export 只影响当前 shell 进程及其子进程,不写入任何配置文件。它适合临时调试、单次任务或 CI/CD 中的环境注入。
常见错误现象:
• 在终端里 export 之后能用某个命令,关掉终端再开就报 command not found
• 写了 export 却发现 systemd 服务、cron 任务、GUI 应用(如 VS Code 启动的终端)都读不到
- GUI 程序通常由 display manager(如 gdm)启动,不读取
~/.bashrc,得改~/.profile或/etc/environment - cron 默认用
/bin/sh,不 source~/.bashrc,必须在 crontab 里显式设置或用bash -c "source ~/.bashrc && cmd" - systemd 服务默认无用户 shell 环境,需在 service 文件中用
Environment=或EnvironmentFile=
~/.bashrc 和 ~/.profile 的分工不能乱
~/.bashrc 是交互式非登录 shell(比如你点终端图标新开一个 tab)加载的;~/.profile 是登录 shell(比如 SSH 登录、图形界面首次登录)加载的。很多用户把所有 export 都塞进 ~/.bashrc,结果 GUI 应用、SSH 登录后首次终端都读不到。
使用场景:
• 开发常用工具(node, rustup, pyenv)一般放 ~/.bashrc,因为日常终端操作多是交互式非登录 shell
• 影响整个会话的路径或全局变量(比如 JAVA_HOME, EDITOR)应放 ~/.profile,确保登录即生效
-
~/.bashrc开头常有[ -n "$PS1" ] || return,这是防止被非交互式 shell 错误加载导致出错 - Ubuntu 桌面版默认不自动 source
~/.bashrc,而是靠~/.profile里的一段逻辑来加载它——但这段逻辑可能被注释或删掉 - 如果你用 zsh,对应的是
~/.zshrc和~/.zprofile,别混用 bash 配置文件
/etc/environment 和 /etc/profile.d/ 的适用边界
/etc/environment 是 PAM 系统级环境配置,格式严格:每行 KEY=VALUE,不支持变量展开、命令替换或 export 关键字。它在用户登录前就被读取,连 shell 都没启动,所以最“底层”也最受限。
而 /etc/profile.d/*.sh 是系统级 shell 初始化片段,会被 /etc/profile source,支持完整 shell 语法,适合部署团队统一环境(比如公司内所有用户都要加 /opt/mytools/bin)。
-
/etc/environment里写PATH="/usr/local/bin:/usr/bin"可以,但写PATH="/my/bin:$PATH"会失效——它不解析$PATH -
/etc/profile.d/myenv.sh必须以.sh结尾,且要有可执行权限(chmod +x),否则不会被加载 - Debian/Ubuntu 默认启用
/etc/environment,RHEL/CentOS 则更依赖/etc/profile.d/,跨发行版部署时要注意
检查环境变量是否真生效,别只信 echo $VAR
echo $PATH 看起来正常,不代表你的程序真能用到——尤其当涉及符号链接、多版本共存、shell 内置命令覆盖时。真正可靠的验证方式是模拟目标上下文执行。
常见错误现象:
• echo $JAVA_HOME 有值,但 java -version 报错或版本不对
• which node 返回 A 路径,node --version 却是 B 版本(说明 PATH 顺序或 shell 函数干扰)
- 用
type -a cmd查看命令所有匹配位置(alias/function/binary),比which更准 - 在子 shell 中测试:
bash -c 'echo $PATH; mycmd --help',排除当前 shell 缓存干扰 - GUI 应用下终端:先运行
ps -o comm= -p $PPID看父进程,如果是gnome-session或gdm,就得确认~/.profile是否被正确加载










