Linux 环境变量指北(指南)
本文更多注重于整理 Linux 环境变量的加载机制,包括 Login Shell、Systemd、图形界面等场景下的环墫变量加载方式。
如果是第一次相识这些,需要读者自行先相识一些前置知识。
关键字:环境变量,environment variable,shell,bash,zsh,终端,systmed,ubuntu,archlinux
作为Linux用户肯定遇到过这样的场景:在终端里配置好的环境变量,一打开图形界面就“神秘失踪”;大概在KDE下正常的程序,换到GNOME却死活读不到JAVA_HOME。这背后的原因,每每与环境变量的加载机制在不同场景下的差异有关。
Linux 系统启动流程
一、终端:Login Shell
Unix shell 是为 Unix 和类 Unix 系统提供传统用户界面的下令行解释器或 shell,通过实行用户输入的下令文本,或包罗下令的文本脚本来指导盘算机的运行。
兼容 Bourne Shell 的 Shell 有:Bash、Zsh 等。其他类型的 Shell 有:Fish、PowerShell、nushell 等。
环境变量提供了一种在多个程序和历程间共享配置的简单方式。 在 Windows 中,通过 GUI 的方式设置全局环境变量非常方便。 而在 Linux 中,通过 Login Shell 配置环境变量是一种常见的做法,虽然原始,但是功能更增强大。
在 linux 下,图形界面启动的终端通常是 Non-Login Shell(不通过 bash --login 启动),只会读取~/.bashrc(交互式配置),而不会触发对应Login Shell的初始化流程。 因此,相识 Login Shell 对于设置环境变量非常重要。
当你通过SSH登录服务器,或是在物理机上按下Ctrl+Alt+F5进入文本终端时,系统会启动一个 Login Shell。
Login Shell 是一种调用模式,在这种模式下,Shell 读取一次性初始化文件。 例如兼容 Bourne Shell 的 Shell 会读取系统范围的 /etc/profile、用户的 ~/.profile(sh)/.bash_profile(bash)/.zprofile(zsh) 或其他 dotfiles。 在登录时, /etc/profile 会读取 /etc/profile.d/ 中任何可读的 *.sh 文件:这些脚本不需要 shebang,也不需要具有可实行权限。它们用于设置环境并定义特定于应用程序的设置。
这些文件(dotfiles)将会设置初始环境,且会被所有从 Shell 启动的历程继续。 因此,其应当只在会话开始(登陆)时读取一次。 例如,在控制台或通过 SSH 登录、使用 --login 参数通过 sudo 或 su 切换用户、手动调用 Login Shell(例如,通过 bash --login)。
不同的发行版使用的 /bin/sh 大概不同,例如 Debian 系默认使用 dash,而 Arch 系默认使用 bash。 在 ~/.bash_profile、~/.zprofile 中引用 ~/.profile,并统一在 ~/.profile 中设置环境变量,可以保证在不同的情况(greetd、uwsm 只使用 sh)下都能见效。
Zsh 和 Bash 有肯定的相似性,主要区别在于 Bash 将 Login shell 的启动文件与交互式(interactive)shell 分开。 正如 Debian wiki 页面所解释的那样:
那么,为什么 .bashrc 是独立于 .bash_profile 的文件呢? 这样做主要是由于汗青原因,当时的机器与本日的工作站相比非常慢。 处理 .profile 或 .bash_profile 中的下令大概需要相称长的时间,尤其是在大量工作必须由外部下令完成的机器上。 因此,困难的初始设置下令(创建可以传递给子历程的环境变量)被置于.bash_profile。 未继续的暂时设置和别名被放在 .bashrc 中,以便每个 subshell 都可以重新读取它们。
虽然说通常情况下交互式的(Interactive) Login Shell(bash -li)不怎么会被用到,但是在一些特殊情况下,比如通过 SSH 登录服务器,大概在 tty 中切换用户,大概是使用 macOS 系统,这种情况下就会用到 Interactive Login Shell。
标准的解决方法是始终在 .bash_profile 文件末尾包罗雷同于以下下令的内容:- [[ -f "${HOME}/.profile" ]] && . "${HOME}/.profile"
- [[ -f "${HOME}/.bashrc" ]] && . "${HOME}/.bashrc"
复制代码 zsh 下,无论是否是 Login Shell,都会加载交互式配置(~/.zshrc)。
Zsh 因其强大的功能和友好的交互体验,逐渐成为主流Shell,目前 Apple 将其作为 macOS 的默认Shell。 在 archlinux 中,/etc/zsh/zprofile 包罗了 emulate sh -c 'source /etc/profile',用于设置$PATH及其他环境变量,以及应用程序相干的设置(/etc/profile.d/*.sh)。 因此使用zsh作为Login Shell也会加载/etc/profile。
对于 macOS,约定是将每个新终端作为 Interactive Login Shell 启动。 macOS GUI 在登录时不运行 .profile,这显然是由于它有自己的加载全局设置的方法。 但这意味着 macOS 上的终端模拟器确实需要运行 .profile(通过告诉它启动的 shell 它是一个登录 shell),否则最终会得到一个不能使用的 shell。
不同shell的配置加载次序(精简)详见1 2:
通常情况下:
- 终端相干配置(如别名、提示符)放用户配置,如~/.bashrc; .zshrc
- 需要全局见效的变量(如JAVA_HOME)放~/.bash_profile; .zprofile 大概统一放在 ~/.profile
- ~/.profile 必须与 /bin/sh 兼容,bashism 语法不支持。
- 如果在 ~/.profile 中设置环境变量,则 ~/.bash_profile 只需加载 .profile 和 .bashrc。
- 只使用 bash 时,同时拥有 ~/.profile 和 ~/.bash_profile 没有什么意义。 如果缺少后者,bash 将很乐意使用前者,并且任何特定于 bash 的行都可以通过检查 $BASH 或 $BASH_VERSION 来保护。
- 在图形桌面环境中启动终端,默认是非login终端,它将仅读取用户的非Login启动脚本。
二、Systemd 的配置方式
随着 Systemd 的普及,一套新的变量加载机制开始取代之前的机制。 具体来说,Systemd 取代了initd,成为系统的第一个历程(PID 等于 1),其他历程都是它的子历程。 Systemd 启动流程抛弃了 shell 脚本,它将系统对象及其依赖项统一为 systemd 单元。 当你登录时,幕后发生了两件关键事情:
优先读取/etc/environment和/etc/security/pam_env.conf(~/.pam_environment 已被弃用)。
/etc/environment 通过定义KEY=VAL配置,实用于所有用户和会话- # /etc/environment
- LANG=en_US.UTF-8
- PATH="/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin"
复制代码 /etc/security/pam_env.conf 同时也支持 VARIABLE [DEFAULT=value] [OVERRIDE=value] 的写法- # /etc/security/pam_env.conf
- LANG DEFAULT=en_US.UTF-8
- # 特殊变量 @{HOME}, @{SHELL},默认值为当前用户的家目录和shell
- # 和 HOME,SHELL 的值无关,默认情况下不会设置它们。
- XDG_CONFIG_HOME DEFAULT=@{HOME}/.config
- # 可以使用 `${VARIABLE}` 在其他变量的值中扩展已定义的变量
- _JAVA_OPTIONS DEFAULT=-Djava.util.prefs.userRoot=${XDG_CONFIG_HOME}/java
- # 虽然支持 KEY=VAL 的写法,但这种写法不支持变量扩展
- PATH="/home/username/bin:/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin"
- # 更推荐
- PATH DEFAULT=@{HOME}/bin:${PATH}
复制代码
- systemd 环境变量environment.d(5)
虽然这里的也是通过 KEY=VAL 的形式定义环境变量,但是支持了变量扩展:- PATH=/opt/foo/bin${PATH:+:$PATH}
- LD_LIBRARY_PATH=/opt/foo/lib${LD_LIBRARY_PATH:+:$LD_LIBRARY_PATH}
- XDG_DATA_DIRS=/opt/foo/share:${XDG_DATA_DIRS:-/usr/local/share/:/usr/share/}
复制代码
- ~/.config/environment.d/*.conf – 用户级
- /etc/environment.d/*.conf
- /run/environment.d/*.conf
- /usr/lib/environment.d/*.conf
- /etc/environment – 向后兼容
一些桌面环境通过 SystemD 用户服务启动程序,这代表着需要通过 environment.d,大概其他特定于桌面环境的方式(KDE)(GNOME)设置环境变量。 (注:通常情况下 Display Manager 设置的环境变量会导入 session)
三、图形界面
DM(Display Manager) 显示管理器
显示管理器通常是一个图形用户界面程序,它在系统启动完成后加载,取代了传统的下令行登录方式。
其负责如下功能:
显示登录窗口(用户名/密码输入界面)
选择桌面环境/窗口管理器(会话类型)
启动Xorg/Wayland显示服务器
Shell 的启动文件(/etc/profile等)是否有效取决于DM。 不同 DM 处理 Login Shell 配置的方式有所不同:
- SDDM(KDE 默认DM)/LightDM: 在 Wayland 和 x11 下都会完整实行 Login Shell 流程并继续环境变量,变量设置相对更加机动。 但是目前不支持 environment.d。
- GDM(GNOME 默认DM): 在 X11 会话中,GDM 使用 Login Shell 加载配置文件,同时运行 /etc/X11/xinit/xinitrc 或雷同的初始化脚本。
而在 Wayland 会话中,GDM 不使用 Login Shell,环境变量通过 ~/.config/environment.d/ 或 /usr/share/gdm/env.d/ 设置。 详见
- greetd: 默认行为加载 /etc/profile 和 ~/.profile(通过 source_profile 选项控制)。
Xorg Session
在 Xorg 环境下,可以通过 xprofile 来加载环境变量。 xprofile(~/.xprofile 和 /etc/xprofile) 在 Xorg 会话初始化阶段(窗口管理器启动前)自动实行下令。xprofile 被以下文件加载:
- GDM - /etc/gdm/Xsession
- LightDM - /etc/lightdm/Xsession
- LXDM - /etc/lxdm/Xsession
- SDDM - /usr/share/sddm/scripts/Xsession
Wayland Session
由于 Wayland 不启动任何 Xorg 相干文件,因此 GDM 和 KDE Plasma* 会导入 systemd 用户环境变量(~/.config/environment.d)。
虽然 SDDM/LightDM 不支持 environment.d,但是可以通过在登陆脚本中导入环境变量实现雷同行为:- # use systemd-environment-d-generator(8) to generate environment, and export those variables
- set -o allexport
- source <(/usr/lib/systemd/user-environment-generators/30-systemd-environment-d-generator)
- set +o allexport
复制代码 GNOME
在 Wayland 下,由于 GDM 不加载 Login Shell,因此 GNOME 会话有且仅有会在 Wayland 中使用 Login Shell 重新加载环境变量。
具体来讲,GNOME 通过 gnome-session 启动,gnome-session 实际上是一个 shell 脚本,它会在实行 gnome-session-binary 之前检查自己的第一个参数是否是 -l(Login)*。如果不是,则重新启动当前 shell 会话为登录 shell。
免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作!更多信息从访问主页:qidao123.com:ToB企服之家,中国第一个企服评测及商务社交产业平台。 |