Linux 环境变量:从 printenv 到 export 与持久化配置
本文要点
- 环境变量是键值对形式的全局配置,影响程序行为,可用
printenv、env、echo $VAR查看 - 临时变量只对单条命令生效,
export让子进程继承,unset删除变量 - 引用变量用双引号保持展开,用
${VAR}做变量名拼接,用${VAR:-默认值}给缺省兜底 - 持久化配置分系统级
/etc/environment、/etc/profile.d/与用户级~/.bashrc、~/.profile - 常见坑:
sudo默认清空环境变量、非交互 shell 不读~/.bashrc、PATH 被覆盖找不到命令
环境变量是什么
环境变量(Environment Variable)是操作系统为进程提供的键值对配置,可以理解成一组"全局设置项"。程序运行时通过读取这些变量来决定行为,比如去哪个目录找可执行文件、用哪种语言输出提示、把临时文件放哪里。
# 形如 KEY=VALUE 的键值对
HOME=/root
LANG=C.UTF-8
PATH=/usr/local/sbin:/usr/bin:/bin与普通 shell 变量不同,环境变量有两个特点:
- 全局可见:一旦设置,当前 shell 和它启动的所有子进程都能读到;
- 跨程序生效:任何语言写的程序(C、Python、Go…)都可以通过系统接口读环境变量,这是 Linux 程序间传递配置最基础的方式之一。
查看环境变量
printenv 查看指定变量
printenv 可以一次查看多个指定变量的值:
printenv HOME SHELL LANG USER
图中的输出告诉我们:主目录是 /root、默认 shell 是 /bin/bash、语言环境是 C.UTF-8、当前用户是 root。
env 列出全部变量
不带参数执行 env 会列出当前 shell 的全部环境变量:
env | head -5echo 快速读取
在 shell 中更常用的是直接用 $ 前缀展开变量:
echo "当前用户: $USER, 主目录: $HOME"注意:$展开发生在双引号内,所以上面的输出是"当前用户: root, 主目录: /root",而不是字面$USER。
临时变量:只对单条命令生效
命令前缀方式
如果只想让一条命令临时带个配置,直接在命令前加 KEY=VALUE 即可,不污染当前 shell:
VAR=hello bash -c 'echo $VAR'这条命令临时为 bash 设置了 VAR=hello,输出 hello,但当前 shell 里并不存在 VAR。
变量赋值 vs 环境变量
在 shell 里直接写 VAR=hello 只是定义了一个 shell 变量,子进程读不到;只有 export 之后才变成环境变量,能被子进程继承:
export VAR=world # 导出为环境变量,子进程可见
echo $VAR # world
unset VAR # 删除该变量
echo $VAR # 空
图中演示了完整生命周期:
- 第一条命令
VAR=hello bash -c 'echo $VAR'输出hello,变量只对子进程生效; export VAR=world后echo $VAR输出world;unset VAR删除变量,最后的echo $VAR输出为空。
变量引用与拼接
双引号与单引号的区别
双引号内的 $VAR 会展开,单引号内的会原样保留:
NAME=Linux
echo "双引号: $NAME" # 输出: 双引号: Linux
echo '单引号: $NAME' # 输出: 单引号: $NAME${VAR} 变量名拼接
当变量名后面紧跟其他字符时,必须用 ${VAR} 明确边界,否则 shell 会把整段当成变量名:
APP_NAME=nginx
echo "版本号: ${APP_NAME}-1.24" # 输出: 版本号: nginx-1.24
# echo "版本号: $APP_NAME-1.24" # 错误:shell 会去找变量 APP_NAME-1.24${VAR:-默认值} 缺省兜底
变量没定义时,${VAR:-default} 会展开为默认值,常用于脚本里给配置项兜底:
echo "${NOTSET:-默认值}" # 输出: 默认值
echo "${HOME:-/root}" # 输出: /root子进程继承:export 的作用
环境变量是"从父进程继承给子进程"的。用 export 导出后,任何子进程都能读到:
export INHERITED=yes
bash -c "echo 子进程看到: $INHERITED" # 输出: 子进程看到: yes但要注意两点:
- 反向不传递:子进程里修改的变量不会影响父进程;
- 有例外:
sudo默认会清空大部分环境变量(见下文常见坑)。
持久化配置:让环境变量每次登录都生效
临时设置的变量重启终端就没了。要永久生效,需要写入配置文件。Linux 按"系统级 → 用户级"两级组织:
系统级配置
| 文件 | 作用 | 加载时机 |
|---|---|---|
/etc/environment | 所有用户共用的基础环境变量 | 登录时由 PAM 读取 |
/etc/profile | 全局登录脚本,定义 PATH 等 | 登录 shell 启动时 |
/etc/profile.d/*.sh | 全局环境变量扩展脚本(更推荐) | 被 /etc/profile 自动 source |
查看系统级配置:
cat /etc/environment
ls /etc/profile.d/ | head -6
图中可以看到 /etc/environment 里通过 PATH="..." 形式定义了系统默认搜索路径,而 /etc/profile.d/ 下则放了一堆按功能拆分的脚本(bash_completion.sh、apps-bin-path.sh 等),由 /etc/profile 自动加载。
用户级配置
| 文件 | 作用 | 加载时机 |
|---|---|---|
~/.bashrc | 用户交互式 shell 配置 | 每次打开交互式终端 |
~/.profile | 用户登录配置 | 登录 shell 启动时 |
把环境变量写进 ~/.bashrc,以后每次开终端都自动生效:
echo "export MY_APP_CFG=demo-value" >> ~/.bashrc
source ~/.bashrc
echo $MY_APP_CFG # demo-valuesource(等价.)会立刻在当前 shell 执行文件内容,不必重新登录。
常见坑与注意事项
坑 1:sudo 默认清空环境变量
sudo 出于安全默认重置环境变量,你自己 export 的变量在 sudo 内是读不到的:
export MY_SECRET=abc123
sudo bash -c "echo sudo内: $MY_SECRET" # 输出为空若确实需要保留,用 sudo -E(保留现有环境)或 sudo VAR=value command(指定传递)。
坑 2:非交互 shell 不读 ~/.bashrc
很多脚本在开头有这段保护:
# If not running interactively, don't do anything
[ -z "$PS1" ] && return所以通过 ssh host "source ~/.bashrc; echo $VAR" 这类非交互方式执行时,~/.bashrc 会被直接跳过,变量读不到。要么改用交互式 bash -i,要么把通用变量放到 ~/.profile。
坑 3:PATH 被覆盖后找不到命令
PATH 决定命令查找顺序。一旦被错误覆盖(比如 PATH=/tmp),ls、vim 等命令全部失效:
echo $PATH | tr : "\n" # 分行查看 PATH 里的每个目录
which -a ls # 查看 ls 实际在哪些目录排查思路:先确认 which -a 找得到命令,再检查 PATH 是否丢了目录;恢复用 export PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin。
坑 4:env -i 会完全清空
env -i command 让命令在空环境中运行(测试脚本健壮性常用):
env -i bash -c "echo 清空后 HOME=$HOME" # HOME 为空小结
环境变量是 Linux 下最基础的配置机制,掌握后能少踩很多坑。核心记忆点:
- 查看用
printenv/env/echo $VAR; - 临时用在命令前加
KEY=VALUE,持久用写配置文件并source; - export 让子进程继承,unset 删除,
${VAR}拼接,${VAR:-def}兜底; - 系统级写
/etc/profile.d/,用户级写~/.bashrc或~/.profile。
日常排障时,遇到"明明设置了却不生效",先按「变量有没有 export → 文件有没有被加载 → 是不是 sudo/非交互环境」三步排查,很快就能定位。
评论 (0)
暂无评论,快来抢沙发吧!