环境变量配了但不生效,多半不是语法写错,而是写进了当前 shell 不读取的文件。判断顺序应该是:先确认这个变量由谁、在什么场景下使用(当前终端、登录会话、systemd 服务、cron 任务),再决定写进哪个文件,最后用新的会话验证,而不是只在当前窗口 source 一下就当成功。下面的路径按这个顺序展开,可以先复制命令逐条跑一遍。
环境变量配置正确与否,取决于「写入位置」和「使用场景」是否匹配,而不是 export 语句本身。交互式非登录 bash 读 ~/.bashrc,登录 shell 读 ~/.profile 或 /etc/profile.d/*.sh,systemd 服务和 cron 任务基本两者都不读,需要用 Environment= 或单独声明。改完必须新开一个会话或用 bash -lc 复验,只在当前窗口 source 后看到值,不能作为配置成功的证据。
Linux环境变量之前先确认这三件事
这三件事缺一个就容易白改:写错文件、权限不足、或者验证方式不对。
- 当前 shell 类型和版本:决定读哪个 rc 文件。执行
echo $SHELL看默认登录 shell,执行ps -p $$ -o comm=看当前进程实际是 bash、zsh 还是 sh。bash 的~/.bashrc与~/.bash_profile分工不同,zsh 读的是~/.zshrc,sh 一般只读~/.profile。 - 权限与生效范围:执行
id -un确认当前用户,执行ls -l /etc/profile.d/ ~/.bashrc看目标文件属主和可写位。改系统级变量需要 root;改~/.bashrc只影响自己。给某个服务用的变量,不要图省事塞进/etc/profile。 - 入口位置:执行
getent passwd $USER看登录 shell 字段,执行systemctl cat 服务名看服务是否用了Environment=或EnvironmentFile=,执行crontab -l看定时任务环境。这三处是「变量在终端里有、在服务里没有」的常见来源。
Linux环境变量:最短可用路径
以一个自定义目录 /opt/app 需要加进 PATH 为例,五步走完。

- 确认当前解释器:
输出应为ps -p $$ -o comm=bash、zsh之类。下面按 bash 写,其他 shell 换成对应 rc 文件。 - 选择写入文件:只给当前用户的交互式终端用,写
~/.bashrc;需要所有用户登录后都有,写/etc/profile.d/app.sh。 - 追加变量,注意用双引号让
$PATH展开:printf '\nexport APP_HOME=/opt/app\nexport PATH="$APP_HOME/bin:$PATH"\n' >> ~/.bashrc - 让当前会话生效并立即看值:
应能看到source ~/.bashrc echo "$APP_HOME" echo "$PATH" | tr ':' '\n' | head -5/opt/app排在 PATH 前列。 - 用新会话复验,这一步才是真正的判据:
bash -lc 'echo $APP_HOME; command -v app'bash -lc模拟登录 shell,bash -c模拟非登录非交互,两个都测一遍就知道写的位置对不对。
Linux环境变量:一个真实场景的完整做法
场景:3 台 Ubuntu 服务器上运行 1 个 Java 服务,进程由 systemd 托管,运行用户为 deploy,JDK 安装在 /usr/lib/jvm/java-17-openjdk-amd64,服务需要读取 JAVA_HOME、APP_HOME=/opt/app 和 LANG=C.UTF-8。如果只在 ~/.bashrc 里 export,systemctl start 起来的进程拿不到这些值,启动时通常报 JAVA_HOME is not set 或中文日志乱码。
正确做法是分两处写:

- 人登录后调试用,写在
/home/deploy/.bashrc:export JAVA_HOME=/usr/lib/jvm/java-17-openjdk-amd64 export APP_HOME=/opt/app export PATH="$JAVA_HOME/bin:$APP_HOME/bin:$PATH" export LANG=C.UTF-8 - 服务运行用,写 unit 文件
/etc/systemd/system/app.service,用EnvironmentFile集中管理更便于以后改:[Service] User=deploy EnvironmentFile=/etc/app/app.env ExecStart=/opt/app/bin/app --config /opt/app/conf/app.yml - 环境文件
/etc/app/app.env,一行一个变量,不要写export,不要加引号:
这个文件属主设为 root、权限JAVA_HOME=/usr/lib/jvm/java-17-openjdk-amd64 APP_HOME=/opt/app PATH=/usr/lib/jvm/java-17-openjdk-amd64/bin:/usr/local/bin:/usr/bin:/bin LANG=C.UTF-8640,避免普通用户改服务环境。 - 重新加载并验证:
systemctl daemon-reload systemctl restart app systemctl show app -p Environment systemctl status app --no-pagersystemctl show的输出里应能看到这三个变量的实际值。
Linux环境变量:跑不通先查这三处
卡点一:当前窗口有效,新开窗口或服务里失效。典型表现是刚 source 完一切正常,重开终端执行 java -version 报 -bash: java: command not found。检查位置:echo $SHELL 与 ps -p $$ -o comm= 是否一致;变量是否只写在了 ~/.bash_profile 而当前是非登录终端;服务侧看 systemctl show 服务名 -p Environment,为空说明没写进 unit 或 EnvironmentFile 路径不对。

卡点二:PATH 被覆盖或没有展开。写成 export PATH=/opt/app/bin 会丢掉系统路径,随后执行 ls 报 -bash: ls: command not found;写成单引号 export PATH='$APP_HOME/bin:$PATH' 则字面量不会展开。检查位置:echo "$PATH" | tr ':' '\n' 确认 /usr/bin、/bin 仍在,且自定义目录顺序正确。
卡点三:语句本身写坏。最常见的报错是 bash: export: /opt/app': not a valid identifier,原因是等号两侧多了空格,export APP_HOME = /opt/app 会被当成三个参数;另外变量值含空格却没加引号,也会让后续解析错位。检查位置:bash -n ~/.bashrc 做语法检查,cat -A /etc/app/app.env 看是否存在 Windows 换行符 ^M 或行尾空格,这两类问题在复制粘贴时很常见。