使用su - user切换用户后$XDG_RUNTIME_DIR目录未创建且环境变量未定义的问题咨询
问题场景
我在使用su - user切换到普通用户后遇到了以下异常:
administrateur@localhost:~$ su - test Password: test@localhost:~$ systemctl --user Failed to connect to bus: $DBUS_SESSION_BUS_ADDRESS and $XDG_RUNTIME_DIR not defined (consider using --machine=<user>@.host --user to connect to bus of other user) test@localhost:~$ ls /run/user/$UID ls: cannot access '/run/user/1004': No such file or directory test@localhost:~$ groups test test@localhost:~$ logout administrateur@localhost:~$
之后尝试用sudo loginctl enable-linger test让用户会话持久化,虽然/run/user/$UID目录及其中的bus文件出现了,但XDG_RUNTIME_DIR环境变量仍然未被定义:
administrateur@localhost:~$ sudo loginctl enable-linger test administrateur@localhost:~$ sudo su - test test@localhost:~$ ls /run/user/$UID/bus /run/user/1004/bus test@localhost:~$ echo $XDG_RUNTIME_DIR test@localhost:~$ logout administrateur@localhost:~$
原因分析
这是因为su -虽然会模拟用户的登录环境,但它并没有通过systemd的logind服务创建完整的用户会话。XDG_RUNTIME_DIR这类变量是logind在用户通过正常渠道(图形界面登录、SSH登录等)创建会话时自动注入的,同时还会启动用户专属的systemd实例。
loginctl enable-linger test的作用是让test用户的systemd服务在未登录状态下也保持运行,所以/run/user/$UID目录会被保留,但su -切换时并不会触发logind为当前shell会话注入环境变量,因此变量仍然为空。
解决方法
这里提供几种实用的解决方式:
方式一:用
machinectl shell切换用户
这是最稳妥的方案,它会通过logind创建完整的用户会话,自动帮你配置好XDG_RUNTIME_DIR和DBUS相关环境变量:machinectl shell test@切换后执行
systemctl --user就能正常工作,echo $XDG_RUNTIME_DIR也会显示正确路径。方式二:手动设置环境变量(适合必须用su的场景)
如果只能用su - user切换,可以在切换后手动设置这两个关键变量:export XDG_RUNTIME_DIR=/run/user/$(id -u) export DBUS_SESSION_BUS_ADDRESS=unix:path=$XDG_RUNTIME_DIR/bus设置完成后,
systemctl --user就能正常连接到用户总线了。方式三:修改用户bash配置文件(永久生效)
要是希望每次用su -切换到该用户时自动设置变量,可以编辑该用户的~/.bash_profile或~/.bashrc文件,添加以下内容:if [ -z "$XDG_RUNTIME_DIR" ]; then export XDG_RUNTIME_DIR=/run/user/$(id -u) export DBUS_SESSION_BUS_ADDRESS=unix:path=$XDG_RUNTIME_DIR/bus fi这样每次登录该用户shell时,都会自动检查并设置变量(前提是已经执行过
loginctl enable-linger确保/run/user/$UID目录存在)。
备注:内容来源于stack exchange,提问作者SebMa

