> 技术文档 > MacOS全局环境变量设置指南_Mac终端环境变量生效命令

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

脚本内容如下,它使用 launchctlsetenv 子命令来设置环境变量。

#! /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

  1. 如果 ~/Library/LaunchAgents 目录不存在,则创建它:mkdir -p ~/Library/LaunchAgents
  2. 创建并编辑 ~/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

理财规划