How to Set System Environment Variables in macOS
Intro
macOS 使用 launchd
进程来管理守护进程和代理,而你还可以用它来运行 shell 脚本。你不与 launchd 直接交互,而是使用 launchctl 命令来载入或卸载 launchd
守护进程和代理。
在系统启动期间,launchd
是内核在设置电脑时首先运行的进程。若你想要 shell 脚本作为守护进程运行,应由 launchd
来启动它。其他用于启动守护进程和代理的机制可能会被 Apple 酌情移除。
你可以通过在以下文件夹中查看配置文件来了解由 launchd
管理的各种守护进程和代理:
文件夹 | 用途 |
---|---|
/System/Library/LaunchDaemons | Apple 提供的系统守护进程 |
/System/Library/LaunchAgents | Apple 提供的基于每个用户且所有用户适用的代理 |
/Library/LaunchDaemons | 第三方系统守护进程 |
/Library/LaunchAgents | 基于每个用户且所有用户适用的第三方代理 |
~/Library/LaunchAgents | 仅适用于登录用户的第三方代理 |
许多教程在设置 macOS 环境变量时,建议在 ~/.bash_profile
或 ~/.zshrc
等位置设置环境变量。这只对 bash/zsh 会话生效。例如在 /etc/bashrc
写入 export NAME="GnixAij"
,但该变量在 zsh 会话中是不可见的,第三方 shell 基本也不会读取
Example Case
这里以设置 XDG_*
系列变量为例进行演示。关于 XDG 规范的介绍,可查阅 XDG Base Directory - ArchWiki。
步骤 1:创建环境设置脚本
首先,在任意位置创建一个 Shell 脚本,例如 ~/.local/bin/sys_envs
。
1
touch ~/.local/bin/sys_envs
脚本内容如下,它使用 launchctl
的 setenv
子命令来设置环境变量。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
#! /bin/bash
# 封装一个函数来设置环境变量,为了可扩展性
env() {
os_name=$(uname -s)
case "$os_name" in
Darwin)
# For macOS, use launchctl to set environment variables
launchctl setenv "$1" "$2"
;;
Linux)
export "$1=$2"
;;
*)
echo "Unsupported OS: $os_name"
exit 1
;;
esac
}
env XDG_BIN_HOME "$HOME/.local/bin"
env XDG_CACHE_HOME "$HOME/Library/Caches"
env XDG_CONFIG_HOME "$HOME/.config"
env XDG_CONFIG_DIRS "/etc/xdg"
env XDG_DATA_HOME "$HOME/.local/share"
env XDG_DATA_DIRS "/usr/local/share/:/usr/share/"
env XDG_RUNTIME_DIR "$TMPDIR/runtime-$UID"
env XDG_STATE_HOME "$HOME/.local/state"
# https://wiki.archlinux.org/title/XDG_user_directories
env XDG_DESKTOP_DIR "$HOME/Desktop"
env XDG_DOCUMENTS_DIR "$HOME/Documents"
env XDG_DOWNLOAD_DIR "$HOME/Downloads"
env XDG_MUSIC_DIR "$HOME/Music"
env XDG_PICTURES_DIR "$HOME/Pictures"
env XDG_PUBLICSHARE_DIR "$HOME/Public"
env XDG_VIDEOS_DIR "$HOME/Movies"
# Make sure the XDG directories exist
mkdir -p "$XDG_CACHE_HOME" "$XDG_CONFIG_HOME" "$XDG_DATA_HOME" "$XDG_RUNTIME_DIR" "$XDG_STATE_HOME"
# Define paths for common programs with partial XDG support
# https://wiki.archlinux.org/title/XDG_Base_Directory#Partial
env CARGO_HOME "$XDG_DATA_HOME/cargo"
env FFMPEG_DATADIR "$XDG_CONFIG_HOME/ffmpeg"
env LESSHISTFILE "$XDG_STATE_HOME/less_history"
env MYPY_CACHE_DIR "$XDG_CACHE_HOME/mypy"
env NODE_REPL_HISTORY "$XDG_STATE_HOME/node_repl_history"
env PYENV_ROOT "$XDG_DATA_HOME/pyenv"
env PYTHONPYCACHEPREFIX "$XDG_CACHE_HOME/python"
env PYTHONUSERBASE "$XDG_DATA_HOME/python"
env PYTHON_HISTORY "$XDG_STATE_HOME/python_history"
env RIPGREP_CONFIG_PATH "$XDG_CONFIG_HOME/ripgrep/config"
env RUSTUP_HOME "$XDG_DATA_HOME/rustup"
env WORKON_HOME "$XDG_DATA_HOME/virtualenvs"
# docker
env DOCKER_CONFIG "$XDG_CONFIG_HOME/docker"
env MACHINE_STORAGE_PATH "$XDG_DATA_HOME/docker_machine"
# npm
env NPM_CONFIG_USERCONFIG "$XDG_CONFIG_HOME/npm/npmrc"
# zsh
env ZDOTDIR "$XDG_CONFIG_HOME/zsh"
env ZSH_PROFILE "$XDG_CONFIG_HOME/zsh/profile"
# yazi
env YAZI_CONFIG_HOME "$XDG_CONFIG_HOME/yazi"
Step 2. Load the script at Login/StartUp
- 如果
~/Library/LaunchAgents
目录不存在,则创建它:mkdir -p ~/Library/LaunchAgents
- 创建并编辑
~/Library/LaunchAgents/env.plist
文件,写入以下内容。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>Label</key>
<string>com.user.environment-vars</string>
<key>ProgramArguments</key>
<array>
<!-- 这里需要替换成你自己的脚本路径 -->
<string>/Users/gjx/.local/bin/sys_envs</string>
</array>
<key>RunAtLoad</key>
<true />
<key>KeepAlive</key>
<false />
</dict>
</plist>
完成以上步骤后,下次登录时,launchd
就会自动执行该脚本,从而设置好所有环境变量。
Limitations
Apple 不保证 launchd
加载服务的确切顺序,也就是可能先重启了Terminal,而后env.plist
才被加载,这会导致 Terminal 无法获取到新的环境变量。
解决方法如下:
- 重新登录:当前用户先Log Out(快捷键
⌘ + ⇧ + Q
),再重新Login - 手动重启应用:字面意思
- 禁用会话恢复:在系统设置中,关闭“Reopen windows when logging back”的功能。
另外就是无法通过 launchctl
修改 PATH
环境变量,想在 System-Wide 层级设置 PATH
,需要在 /etc/paths
中修改。
Ref
How to Set System Environment Variables in macOS