001-macos配置环境变量
对,你的痛点很常见:每加一条变量要改好几处。给你一套「单一真源」方案——只维护一个 .env 文件,其它地方固定不变,同时满足:
-
Zsh 终端可读
-
IntelliJ IDEA 等 GUI 程序可读(从 Dock/Spotlight 启动也可以)
-
重新登录 & 重启后仍生效
下面一次性配好,以后只改 .env。
一次性安装(只做一遍)
1) 建一个统一的变量文件
mkdir -p ~/.config/env
nano ~/.config/env/global.env
写入你要的变量(支持注释,等号两边别留空格):
# 全局环境变量(示例)
DASHSCOPE_API_KEY=sk-xxxx
JAVA_HOME=/Library/Java/JavaVirtualMachines/jdk-21.jdk/Contents/Home
2) 让 Zsh 永远自动读它(给所有终端)
把这一段追加到 ~/.zshenv(只做一次):
# Load global envs (single source of truth)
if [ -f "$HOME/.config/env/global.env" ]; then
# shellcheck disable=SC2046
export $(grep -v '^\s*#' "$HOME/.config/env/global.env" | grep -v '^\s*
这样**所有 zsh 终端**都会加载 global.env(.zshenv 在 zsh 启动时加载,比 .zprofile/.zshrc 更早)。关于各 zsh 文件职责的差异可参考 Apple/社区讨论。
> 立刻生效:
source ~/.zshenv
## **3) 让 GUI 应用也吃到这些变量(通过 LaunchAgent)**
做一个**登录时自动执行**的小脚本,把 global.env 注入到 GUI 会话的 launchd 环境里(等同 “系统 GUI 会话环境变量”):
### **(a) 注入脚本**
mkdir -p ~/.local/bin
nano ~/.local/bin/load-global-env-to-launchd.sh
写入:
#!/bin/zsh
ENV_FILE="
逐行读取 KEY=VAL(忽略空行与注释)
while IFS='=' read -r key value; do
[[ -z "
去掉可能的引号
value="
value="
/bin/launchctl setenv "
done < "$ENV_FILE"
并赋权:
chmod +x ~/.local/bin/load-global-env-to-launchd.sh
> 为什么这样做?因为 GUI 应用**不会继承你的 shell 文件**,而是继承 **launchd** 的会话环境。用 launchctl setenv 注入到登录会话,就能让 **IDEA、VSCode、Chrome 等**都能读取这些变量。官方与社区都推荐用 **LaunchAgent + launchctl** 实现 GUI 级环境变量,且可跨重启持久生效。
### **(b) LaunchAgent(登录时自动执行脚本)**
mkdir -p ~/Library/LaunchAgents
nano ~/Library/LaunchAgents/com.user.globalenv.plist
写入:
加载(或直接重启后自动加载):
launchctl load ~/Library/LaunchAgents/com.user.globalenv.plist
说明:早年 ~/.MacOSX/environment.plist 与 /etc/launchd.conf 等方式已被废弃/不再生效,用 LaunchAgent 是现在通行做法。
以后使用(只改一个地方)
新增 / 修改变量 → 只编辑这一个文件:
nano ~/.config/env/global.env
保存后让 GUI 会话即刻更新(无需注销):
~/.local/bin/load-global-env-to-launchd.sh
终端会话里也会在新开窗口时自动加载;若要当前终端马上生效:
source ~/.zshenv
验证:
-
终端:printenv DASHSCOPE_API_KEY
-
IntelliJ:新启动的 IDEA 里运行一个小 Java 程序 System.getenv("DASHSCOPE_API_KEY")
-
系统 GUI 会话:launchctl getenv DASHSCOPE_API_KEY
常见问答
-
为啥不用只改 .zprofile/.zshrc?
它们只影响 shell;Dock/Spotlight 启动的 GUI 应用看不到。
-
为什么不是 ~/.MacOSX/environment.plist?
已经过时/在新系统上不可靠。
-
direnv 要不要用?
适合按目录自动切换项目变量,但它解决的是项目级问题,GUI 全局变量仍需 launchctl 路子;两者可并存。
需要的话,我可以把以上步骤打包成一键初始化脚本(创建 global.env、脚本、plist 并自动加载)。你只要粘贴运行即可。 | xargs -I{} echo {})
fi
这样**所有 zsh 终端**都会加载 global.env(.zshenv 在 zsh 启动时加载,比 .zprofile/.zshrc 更早)。关于各 zsh 文件职责的差异可参考 Apple/社区讨论。
> 立刻生效:
{{CODE_BLOCK_3}}
## **3) 让 GUI 应用也吃到这些变量(通过 LaunchAgent)**
做一个**登录时自动执行**的小脚本,把 global.env 注入到 GUI 会话的 launchd 环境里(等同 “系统 GUI 会话环境变量”):
### **(a) 注入脚本**
{{CODE_BLOCK_4}}
写入:
{{CODE_BLOCK_5}}
并赋权:
{{CODE_BLOCK_6}}
> 为什么这样做?因为 GUI 应用**不会继承你的 shell 文件**,而是继承 **launchd** 的会话环境。用 launchctl setenv 注入到登录会话,就能让 **IDEA、VSCode、Chrome 等**都能读取这些变量。官方与社区都推荐用 **LaunchAgent + launchctl** 实现 GUI 级环境变量,且可跨重启持久生效。
### **(b) LaunchAgent(登录时自动执行脚本)**
{{CODE_BLOCK_7}}
写入:
{{CODE_BLOCK_8}}
加载(或直接重启后自动加载):
{{CODE_BLOCK_9}}
> 说明:早年 ~/.MacOSX/environment.plist 与 /etc/launchd.conf 等方式已被废弃/不再生效,用 LaunchAgent 是现在通行做法。
---
# **以后使用(只改一个地方)**
**新增 / 修改变量** → 只编辑这一个文件:
{{CODE_BLOCK_10}}
保存后让 GUI 会话即刻更新(无需注销):
{{CODE_BLOCK_11}}
终端会话里也会在新开窗口时自动加载;若要当前终端马上生效:
{{CODE_BLOCK_12}}
> 验证:
- 终端:printenv DASHSCOPE_API_KEY
- IntelliJ:新启动的 IDEA 里运行一个小 Java 程序 System.getenv("DASHSCOPE_API_KEY")
- 系统 GUI 会话:launchctl getenv DASHSCOPE_API_KEY
---
## **常见问答**
- **为啥不用只改 .zprofile/.zshrc?**
它们只影响 shell;Dock/Spotlight 启动的 GUI 应用看不到。
- **为什么不是 ~/.MacOSX/environment.plist?**
已经过时/在新系统上不可靠。
- **direnv 要不要用?**
适合按目录自动切换项目变量,但它解决的是**项目级**问题,GUI 全局变量仍需 launchctl 路子;两者可并存。
---
需要的话,我可以把以上步骤打包成一键初始化脚本(创建 global.env、脚本、plist 并自动加载)。你只要粘贴运行即可。