MacOS全局环境变量设置指南_Mac终端环境变量生效命令
原文发布于Set System Environment Variables in macOS - vluv’s space
Intro
许多教程在设置 macOS 环境变量时,建议在 ~/.bashrc
或 ~/.zshrc
等文件内设置环境变量。这种方式是十分简单的,大多数情况下也没有问题。
其局限是,上述方案只是修改 Shell 的配置文件,这只对 bash/zsh 会话生效。个人偶尔会在 nushell 和 zsh 直接切换(问就是闲的),如果只用一种 shell,那么这也算不上什么局限。
要么在每个 Shell 的配置文件中设置一遍环境变量。或者,只在 ~/.zshrc
中使用 export
设置环境变量,在 zsh 中执行 exec bash
进入bash(or any other shell),这样 ~/.zshrc
中设置的环境变量也能被传递给 bash。这样多少有点丑陋,且有一定的性能开销,虽然对于现代计算机来说这点开销算不了什么
Shell 变量 & 环境变量
Shell 变量:这是一种只在当前 Shell 会话中有效的变量。它不会被该 Shell 启动的其他进程(子进程)所看到。
(zsh)$ x=1(zsh)$ echo $x1(zsh)$ bash(bash)$ echo $x[NO-OUTPUT]
环境变量:这是一种特殊的变量,它不仅在当前 Shell 会话中有效,还会被传递给所有由该 Shell 启动的子进程;
(zsh)$ export x=1(zsh)$ echo $x1(zsh)$ bash(bash)$ echo $x1
Read More: export command in Linux with Examples - GeeksforGeeks
Example Case
这里以设置 XDG_*
系列变量为例进行演示。关于 XDG 规范的介绍,可查阅 XDG Base Directory - ArchWiki。
[!info]
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
仅适用于登录用户的第三方代理
步骤 1:创建环境设置脚本
首先,在任意位置创建一个 Shell 脚本,例如 ~/.local/bin/sys_envs
。
touch ~/.local/bin/sys_envs
脚本内容如下,它使用 launchctl
的 setenv
子命令来设置环境变量。
#! /bin/bash# Define a macro function for setting environment variablesenv() { os_name=$(uname -s) case \"$os_name\" in Darwin) # For macOS, use launchctl to set environment variables launchctl setenv \"$1\" \"$2\" # launchctl setenv does not work for current shell session(which executes this script), # for example, when set `XDG_CONFIG_HOME/bat`, the XDG_CONFIG_HOME will be expanded as empty string. export \"$1=$2\" ;; Linux) export \"$1=$2\" # Replace $HOME with ~ for /etc/environment env_value=\"${2//$HOME/~}\" # Append to /etc/environment with sudo echo \"$1=$env_value\" | sudo tee -a /etc/environment > /dev/null ;; *) 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_STATE_HOME \"$HOME/.local/state\"# https://wiki.archlinux.org/title/XDG_user_directoriesenv 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 existmkdir -p \"$XDG_CACHE_HOME\" \"$XDG_CONFIG_HOME\" \"$XDG_DATA_HOME\" \"$XDG_STATE_HOME\"# Define paths for common programs with partial XDG support# https://wiki.archlinux.org/title/XDG_Base_Directory#Partialenv 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\"# dockerenv DOCKER_CONFIG \"$XDG_CONFIG_HOME/docker\"env MACHINE_STORAGE_PATH \"$XDG_DATA_HOME/docker_machine\"# npmenv NPM_CONFIG_USERCONFIG \"$XDG_CONFIG_HOME/npm/npmrc\"# zshenv ZDOTDIR \"$XDG_CONFIG_HOME/zsh\"env ZSH_PROFILE \"$XDG_CONFIG_HOME/zsh/profile\"env HISTFILE \"~/.cache/zshhistory\"# yazienv 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
文件,写入以下内容。
<!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
- 在 Mac 上的“终端”中使用 launchd 管理脚本 - 官方 Apple 支持 (中国)
- Setting environment variables via launchd.conf no longer works in OS X Yosemite/El Capitan/macOS Sierra/Mojave? - Stack Overflow