看懂什么是环境变量
程序能跑,常常不是因为「装上了」,而是操作系统和进程约定了一套键值:可执行文件在哪些目录、JDK 在哪、代理是谁。这套由操作系统维护、子进程继承的命名变量,就是 环境变量。配不好时,双击图标没事,终端里却报「不是内部或外部命令」——差的就是这份约定。
什么是环境变量
操作系统本身是大型程序,Windows、Linux、macOS 都是。JDK、MySQL、Chrome、微信等应用跑在操作系统之上。
环境变量是操作系统(以及当前进程)用来描述运行环境的命名变量。 名字唯一,值是一段字符串。操作系统自己读,当前进程里启动的应用程序也能读到(子进程默认继承父进程的环境)。
部分软件装完必须再配环境变量才能在终端里当命令用,典型是 JDK、MySQL:除了把安装目录下的 bin 加进 PATH,还常要设 JAVA_HOME 这类「告诉别的程序去哪找我」的变量。
系统变量与用户变量
图形界面里常见两类,日常说「配环境变量」指的就是它们:
- 系统变量:整台机器、所有用户都能读。改它需要管理员权限。
- 用户变量:只对当前登录用户生效,账号之间互相隔离。
这是 Windows 注册表里的分法。Unix、macOS 没有同名的两栏,对应关系是:写在 /etc 下的对全体用户生效,写在家目录(~/.zshrc 等)里的只对当前用户生效。
为什么要配环境变量?
启动程序常见两种方式:双击图标、在终端里敲命令。
- 桌面快捷方式里已经写了程序的完整路径,系统按路径去执行。
- 终端里只敲命令名(如
java)时,系统必须知道磁盘上哪一个文件对应这个名字。三种写法都能跑:
# 完整绝对路径
/usr/bin/java -version
# 先进入程序所在目录(Unix 下当前目录通常不在 PATH 里,仍建议写 ./java)
cd /usr/bin
./java -version
# 只敲命令名,靠 PATH 查找
java -version
没有把 Java 的 bin 写进 PATH 时,直接敲 java -version 会提示找不到命令:系统不知道可执行文件在哪。不配 PATH 也能运行,但每次都要写完整路径。
PATH 怎么查找
PATH 是最常用的环境变量,值是一串目录,专门存放「可以当命令执行的程序」所在的文件夹。
敲一条 没有写路径 的命令时:
- Unix、macOS: 按
PATH里登记的目录 从左到右 查找,找到第一个同名可执行文件就停。 默认不会先搜当前工作目录(除非PATH里显式写了.)。当前目录里的脚本应写成./script.sh。 - Windows(cmd): 会先在当前目录找,再按
PATH里的目录找。这是和 Unix 不同的一点。
目录之间的分隔符:Unix、macOS 用冒号 :,Windows 用分号 ;。
查看 PATH:
echo $PATH
echo %PATH%
查找某个命令实际对应哪个文件:
# Unix、macOS
which java
command -v java
type java
where java
系统推荐的 macOS 改 PATH 方式:不要直接改 /etc/paths(系统更新会覆盖)。在 /etc/paths.d/ 下新建文件(例如 mypath),每行一个目录,由 path_helper 在登录 Shell 时拼进 PATH。这是给 全机 加路径的做法;个人目录写进 ~/.zprofile 即可。
当前终端临时追加(关掉窗口即失效):
export PATH=/example/bin:$PATH
环境变量配置文件在哪?
Shell 在不同场景下读取不同文件,理解这一点是正确配置环境变量的关键。
读取机制:
- Linux
/etc/environment:由 PAM 的pam_env模块在登录时读取,内容是KEY=VALUE列表,不是 Shell 脚本。macOS 不使用此文件。 - macOS
path_helper:登录 Shell 会自动执行/usr/libexec/path_helper(bash 通过/etc/profile,zsh 通过/etc/zprofile),它读取/etc/paths和/etc/paths.d/来拼接系统 PATH。
| 范围 | bash | zsh(macOS Catalina 起默认) |
|---|---|---|
| 系统级 | /etc/profile、/etc/bashrc |
/etc/zprofile、/etc/zshrc |
| 用户级 | ~/.bash_profile、~/.profile、~/.bashrc |
~/.zprofile、~/.zshrc |
加载顺序(bash):
- 登录 Shell:先读
/etc/profile,再依次尝试~/.bash_profile→~/.bash_login→~/.profile(只读第一个存在的)。 - 交互式非登录 Shell:读
/etc/bashrc和~/.bashrc。
macOS Terminal 默认启动的是登录 Shell。若只改 ~/.bashrc 而不在 ~/.bash_profile 中 source 它,新窗口的环境变量将不生效。
加载顺序(zsh):
- 登录时:读
/etc/zprofile→~/.zprofile - 交互时:读
/etc/zshrc→~/.zshrc
PATH 建议写在 ~/.zprofile 或 ~/.zshrc(均在 path_helper 之后执行)。不要写在 ~/.zshenv 中,否则会抢在 path_helper 前执行,导致 PATH 顺序被打乱。
系统级追加(Linux):
Linux 的 /etc/profile 会自动载入 /etc/profile.d/*.sh。如需系统级配置,请在此目录下新建脚本,不要直接修改 /etc/profile 本体。
GUI 程序例外:
从 Dock 或 Spotlight 启动的 GUI 应用不会读取任何 Shell 配置文件(它们走的是 launchd 启动路径)。
终端中生效的环境变量,图形界面应用不一定有——这属于启动机制不同,不是配置错误。
macOS、Linux 配置环境变量
查看
# 当前进程的环境变量(export 出去的)
printenv
env
# 当前 Shell 的变量,范围比环境更大
set
printenv PATH
echo $PATH
echo ${PATH}
临时(只在当前窗口)
关掉终端、新开窗口都会丢掉:
export MY_NEW_VAR="example"
echo $MY_NEW_VAR
永久
写入配置文件,再 source 该文件,或新开终端、重新登录。
系统级(全体用户,需要管理员权限)。能不改 /etc/profile 就不要改:
sudo vim /etc/profile
# 文件内写入
export MY_NEW_VAR="example"
source /etc/profile
当前用户,bash:
vim ~/.bash_profile
export MY_NEW_VAR="example"
source ~/.bash_profile
当前用户,zsh(现行 macOS 默认):
vim ~/.zprofile
export MY_NEW_VAR="example"
source ~/.zprofile
交互式相关的别名、提示符也可以写在 ~/.zshrc。
删除(当前会话)
unset MY_NEW_VAR
只 unset 不会改配置文件;永久删除要把文件里对应的 export 行去掉后再 source。
Windows 配置环境变量
图形界面里同时能改系统变量和用户变量:系统属性 → 高级 → 环境变量(运行 sysdm.cpl 也可打开)。永久生效 以这种配置方法为准。
下面命令默认指 cmd。PowerShell 语法不同:读是 $env:PATH,会话内写是 $env:MY_NEW_VAR="example"。
查看全部:
set
查看单个(例如 PATH):
set PATH
会话内临时设置,关掉该 cmd 窗口即失效,不会写入系统保存的环境变量:
set MY_NEW_VAR=example
set PATH=%PATH%;C:\example\bin
清空当前窗口的 PATH(只影响这个会话):
set PATH=
set 全部是会话级。新开的 cmd 读的是图形界面(或 setx)里存下来的那份。已经打开的窗口不会自动刷新,要关掉重开。
环境变量是进程启动时拷贝的一份表。PATH 可以少写绝对路径;JAVA_HOME 一类则把位置告诉别的程序。改之前分清:临时还是永久、用户还是系统、以及当前这个终端会不会把值传给它拉起的子进程。