Shell 变量:这是一种只在当前 Shell 会话中有效的变量。它不会被该 Shell 启动的其他进程(子进程)所看到。
(zsh)$ x=1 (zsh)$ echo $x 1 (zsh)$ bash (bash)$ echo $x [NO-OUTPUT]
环境变量:这是一种特殊的变量,它不仅在当前 Shell 会话中有效,还会被传递给所有由该 Shell 启动的子进程;
(zsh)$ export x=1 (zsh)$ echo $x 1 (zsh)$ bash (bash)$ echo $x 1
Read More: export command in Linux with Examples - GeeksforGeeks
这里以设置 XDG_*
系列变量为例进行演示。关于 XDG 规范的介绍,可查阅 XDG Base Directory - ArchWiki。
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 | 仅适用于登录用户的第三方代理 |
首先,在任意位置创建一个 Shell 脚本,例如 ~/.local/bin/sys_envs
。
touch ~/.local/bin/sys_envs
脚本内容如下,针对 MacOS 它使用 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"# 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"
前面 Bash 版本的脚本是写入到/etc/environment
中,只支持普通键值对。而/etc/profile.d/*.sh
为 shell script,可以在 value 中引用变量,相对灵活一点。这里给出一个 nushell 版本的脚本,将 Linux 环境变量写入到/etc/profile.d/gnix-env.sh
中
针对个人跨平台需求,这里把环境变量的设置封装成一个 env
函数中,对于 Arch Linux 来说,系统级环境变量可以写入 /etc/environment
或/etc/profile.d/*.sh
中
如需针对单用户设置,可以考虑写入~/.pam_environment
,详见pam_env.conf(5) - Linux man page
#! /usr/bin/env nu# Define a function to set environment variables cross-platformdef --env env [name: string value: string] { # Set env var for current session load-env {$name: $value} match $nu.os-info.name { "macos" => { launchctl setenv $name $value } "linux" => { let env_file = "/etc/profile.d/gnix-env.sh" touch $env_file let lines = (open $env_file | lines | where not ($it | str starts-with $"export ($name)=")) let env_value = ($value | str replace $nu.home-path "$HOME") let updated = ($lines | append $"export ($name)=\"($env_value)\"") $updated | str join (char nl) | save --force $env_file } "windows" => { setx $name $value } }}
~/Library/LaunchAgents
目录不存在,则创建它:mkdir -p ~/Library/LaunchAgents
~/Library/LaunchAgents/env.plist
文件,写入以下内容。<?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
就会自动执行该脚本,从而设置好所有环境变量。
Apple 不保证 launchd
加载服务的确切顺序,也就是可能先重启了 Terminal,而后env.plist
才被加载,这会导致 Terminal 无法获取到新的环境变量。
解决方法如下:
⌘ + ⇧ + Q
),再重新 Login另外就是无法通过 launchctl
修改 PATH
环境变量,想在 System-Wide 层级设置 PATH
,需要在 /etc/paths
中修改。
Set System Env-Vars in UNIX