简介面向 Ubuntu 22.04 及以上版本的 GDM 登录背景修改脚本包针对新版本中 gdm 配置方式调整、旧方法失效的问题设计适合需要个性化登录界面的 Ubuntu 桌面用户和系统管理员。资源共 10 个文件以 shell 脚本为主体辅以说明文档和许可证文件压缩包仅 20KB轻量易用。目前已有 1131 人学习下载。脚本包不仅提供常规背景设置功能还额外包含透明背景处理方案并针对 23.04 前后版本分别提供适配脚本兼容性考虑较周到同时附带 README 说明覆盖备份 gdm 配置、获取 sudo 权限、修改后重启服务等关键步骤可帮助用户规避因配置出错导致无法登录的风险。作为专为新版 Ubuntu 设计的小工具操作路径清晰无需手动深究 gdm 底层配置适合快速完成登录界面个性化改造。1. 为什么 22.04 登录背景改不动GDM3 的资源锁定机制升级到 Ubuntu 22.04 之后很多人会发现一个奇怪现象桌面壁纸想怎么换就怎么换但登录界面的背景永远停留在默认的紫红色渐变上。去“设置 → 背景”里改图登录界面一点反应都没有。原因在于 GDM3 登录背景根本不由壁纸设置控制而是打包在/usr/share/gnome-shell/gnome-shell-theme.gresource这个二进制主题资源里。手动解包、替换、重编译的教程在社区里流传过不少但每次都要敲十几条命令升级一次失效一次。这篇文章把整套流程收敛成一份可反复执行的 bash 脚本覆盖备份、解包、替换、重编译、安装与回滚适合桌面维护者和需要在多台机器上统一登录界面的工程师。2. 动手前的选型两条修改路线与脚本化方案2.1 GDM3 的背景不是壁纸先弄清楚改的是谁Ubuntu 22.04 默认的显示管理器是 GDM3登录界面的渲染由 GNOME Shell 完成。GDM3 启动时不会读取用户会话的壁纸配置而是从一个二进制主题包中加载登录界面的全部资源。这个资源包就是/usr/share/gnome-shell/gnome-shell-theme.gresource登录背景、用户列表样式、输入框、系统菜单的外观全部塞在同一个文件里。要理解“改壁纸为什么无效”得先分清两个进程。用户登录后进入的桌面会话是一套独立的 gnome-shell 进程它读取的是org.gnome.desktop.background这套 dconf 配置而登录界面由更早启动的 GDM 进程负责它读取的是主题资源包里的gnome-shell.css。两套进程互不干扰。手动去改/usr/share/backgrounds/目录里的默认壁纸GDM 进程根本不会扫描那个目录。我在 22.04 虚拟机里反复验证过这个结论换到 24.04 后路径和机制也没有变化变的只是 GNOME Shell 版本号。主题资源包的内部结构并不复杂。用gresource list可以列出内部文件路径常见的有/org/gnome/shell/theme/gnome-shell.css /org/gnome/shell/theme/background.png /org/gnome/shell/theme/noise-texture.png其中gnome-shell.css里控制登录界面背景的节点叫#lockDialogGroup。这个节点的背景属性就是登录背景的最终来源。GDM 的主题引擎会在加载时按 CSS 规则把图片绘制到登录界面。顺带提一句22.04 到 24.04 的主路径没变我手头有一台升到 24.04 的机器依然能用这套资源结构改登录背景所以这个方案并不只适用于 22.04 一个版本。2.2 三条路线对比手动改、社区工具、自写脚本网上流传的改登录背景方法可以归成三类各有各的适用场景。方案持久性系统更新影响上手难度适用场景手动解包重编译较好直到 gnome-shell 更新更新后被覆盖高需要敲十几条命令临时改一次社区现成脚本一般脚本跟不上 GNOME 版本就失效低一条命令跑完快速尝鲜自写脚本好逻辑可控有备份更新后可重跑中需要维护长期维护、批量装机社区里流传较广的gdm-set-background类工具思路很直接但很多版本停留在 GNOME 3.x 的资源结构上。换到 22.04 的 GNOME Shell 42 之后要么找不到gnome-shell-theme.gresource.xml要么重编译出来的资源缺文件登录界面直接黑屏。自己写脚本的好处是能主动适配解包前先用gresource list确认路径替换前先做备份重编译时用系统自带的 XML 描述文件对 GNOME 版本不敏感。需要说明的是自写脚本并不复杂核心命令就三个gresource list、gresource extract、glib-compile-resources。外面套一层 bash加上参数解析和备份逻辑就把一次性的临时操作变成了可重复交付的运维脚本。2.3 脚本化要解决的四个问题备份、解包、重编译、重启我习惯把这类脚本的职责拆成四块备份、解包、替换并重编译、安装并重启。备份不是可选项而是第一步。重编译后的 gresource 如果格式损坏GDM 可能连渲染都失败用户看到的就是黑屏或紫屏。所以脚本第一步永远是把原文件复制为带时间戳的.bak文件。第二块是解包完整性。gresource extract一次只能提取一个资源必须靠gresource list配合循环才能完整展开整个目录。只提取 CSS 而漏掉纹理文件重编译后会得到一份缺资源的主题包登录界面会进入降级模式。第三块是图片预处理。CSS 里的background-size: cover会等比缩放图片但比例差太多时图片内容会被裁掉所以脚本里通常先把图片裁切到 16:9 或目标屏幕分辨率。第四块是重启策略。systemctl restart gdm会结束当前所有图形会话脚本默认不自动重启而是通过--restart参数显式控制避免远程维护时把当前会话直接踢掉。3. 写一个可复用的登录背景脚本解包、替换、重编译全拆解3.1 运行前检查依赖与当前会话感知先看脚本的开头部分这一步解决依赖预检和权限问题。#!/usr/bin/env bash set -euo pipefail if [[ ${EUID} -ne 0 ]]; then echo 必须以 root 运行sudo $0 2 exit 1 fi for cmd in gresource glib-compile-resources convert; do if ! command -v $cmd /dev/null 21; then echo 缺少 $cmd先执行 sudo apt install libglib2.0-bin imagemagick 2 exit 1 fi done THEME_GRESOURCE/usr/share/gnome-shell/gnome-shell-theme.gresource if [[ ! -f $THEME_GRESOURCE ]]; then echo 找不到 $THEME_GRESOURCE确认当前桌面环境是 GDM3 2 exit 1 fiset -euo pipefail是 bash 脚本的基础防御任何一个命令失败都立即退出避免带着半成品继续执行。root 检查放在最前面防止后续写入系统目录时报权限错误。依赖检查用command -v而不是which因为后者在 systemd timer 或 cron 的精简 PATH 环境下可能不存在。gresource和glib-compile-resources属于libglib2.0-bin包convert属于imagemagick。如果目标机器是最小化安装的服务器这个检查会在执行前给出明确的安装提示而不是等脚本中途报错。3.2 解包 gresource用 for 循环逐文件提取接下来进入解包环节。这个步骤不能用一条命令完成需要把资源列表读入循环逐个提取。WORKDIR$(mktemp -d) trap rm -rf $WORKDIR EXIT cd $WORKDIR mkdir -p theme # 列出资源包内部所有路径逐个提取到 theme 目录 while IFS read -r res_path; do rel_path${res_path#/org/gnome/shell/theme/} mkdir -p theme/$(dirname $rel_path) gresource extract $THEME_GRESOURCE $res_path theme/$rel_path done (gresource list $THEME_GRESOURCE)这段代码的逻辑不算复杂。gresource list输出形如/org/gnome/shell/theme/gnome-shell.css的完整路径循环里用参数展开#把前面的固定前缀去掉得到相对路径。gresource extract把二进制内容写出到本地文件保持目录结构不变。trap保证脚本无论是正常退出还是中途报错临时目录都会被清理不会在/tmp里堆积垃圾。这里有一个常见的漏项XML 描述文件。重编译需要/usr/share/gnome-shell/gnome-shell-theme.gresource.xml作为输入之一它不在 gresource 内部需要单独复制进工作目录。大部分 Ubuntu 发行版自带这个 XML我在脚本里会加一层判断不存在时明确报错而不是静默继续。有人会图省事直接去改/usr/share/gnome-shell/gnome-shell.css那个文件对 GDM 进程完全不生效只对部分用户会话有效属于典型的选错修改对象。3.3 图片预处理与 CSS 注入convert 和追加规则解包完成后把用户传入的图片处理成标准尺寸并往 CSS 里追加自定义规则。SRC_IMG${1:?用法: $0 图片路径 [--blur] [--restart]} # 裁到 16:9避免登录界面拉伸 convert $SRC_IMG -auto-orient -gravity center \ -resize 1920x1080^ -extent 1920x1080 theme/background.png # 追加覆盖规则不破坏原有 CSS 结构 cat theme/gnome-shell.css EOF /* custom login background */ #lockDialogGroup { background-image: url(background.png); background-size: cover; background-repeat: no-repeat; } EOF第一条convert命令里的1920x1080^是 ImageMagick 的裁切语法先按最短边等比缩放保证图片完全覆盖目标区域再居中裁出 1920x1080。-auto-orient处理手机竖图常带的 EXIF 旋转信息避免图片方向错误。第二条命令把背景规则追加到 CSS 末尾采用追加而不是 sed 替换是因为不同版本里#lockDialogGroup的原始写法不一样追加规则不依赖原文件内容兼容性更好。GNOME Shell 的 CSS 引擎不认background简写里的/语法所以要拆成background-image和background-size两行。图片路径含空格时调用脚本需要给参数加引号这一点我在脚本注释里会写明。3.4 重编译与安装输出到临时文件再整体替换编译和安装是风险最集中的一步输出位置必须先指向临时文件。cd theme glib-compile-resources --sourcedir. \ --target$WORKDIR/gnome-shell-theme.gresource \ /usr/share/gnome-shell/gnome-shell-theme.gresource.xml BACKUP${THEME_GRESOURCE}.bak.$(date %Y%m%d%H%M%S) cp $THEME_GRESOURCE $BACKUP install -m 0644 $WORKDIR/gnome-shell-theme.gresource $THEME_GRESOURCE echo 已备份到 $BACKUP if [[ ${2:-} --restart ]]; then systemctl restart gdm figlib-compile-resources的--sourcedir指向刚才解包出来的 theme 目录输出目标使用临时路径编译完成后用install -m 0644覆盖系统文件。这样可以保证编译失败时不会破坏线上的资源包只有完整编译成功后才会写入。备份文件带时间戳之后想回滚只需要从备份恢复。--restart参数控制是否重启 GDM我一般会在交互式终端里执行时不加这个参数先人工检查一遍输出再决定是否重启。注意systemctl restart gdm会结束当前所有图形会话。如果你正在本机桌面操作不要直接跑这个命令建议在 tty 或 ssh 会话里执行并保证有字符终端通道可以兜底。3.5 安装到 /usr/local/sbin 并跑通第一次脚本写完后我习惯把它安装到/usr/local/sbin/然后按固定格式调用。sudo install -m 0755 set-login-background.sh /usr/local/sbin/set-login-background.sh sudo /usr/local/sbin/set-login-background.sh /data/wallpapers/desktop.jpg --restart第一次执行建议先不传--restart跑完用gresource list确认资源包内容再手动重启 GDM。原因是如果图片预处理或 CSS 注入有问题不重启就不会影响当前会话可以在黑屏发生之前修正。第一次跑通之后后续修改背景只需要替换图片路径重跑脚本。这里补充一个 shell 脚本入门的细节整个脚本没有用任何 bash 高级特性for循环、参数展开、重定向都是基础语法新手顺着代码走一遍就能读懂每一行在做什么。4. 进阶定制模糊、暗色遮罩、轮换与批量装机4.1 模糊与暗色遮罩用 ImageMagick 预处理而不是 CSS blur登录界面除了背景图还要保证用户名输入框和密码框可读。白底图片或高亮风景图会让输入框变得难以辨认常见做法是叠加一层半透明黑色遮罩或者把背景图模糊处理。关键点在于这两件事要在 ImageMagick 阶段完成而不是写进 GNOME Shell 的 CSS。# 生成模糊版本半径 8 是常用起点 convert $SRC_IMG -filter Gaussian -blur 0x8 -auto-orient \ -gravity center -resize 1920x1080^ -extent 1920x1080 theme/background.png # 叠加 35% 黑色增强文字对比度 convert theme/background.png -fill black -colorize 35 theme/background.png-blur 0x8的意思是横向半径由算法自动推导纵向半径固定为 8。半径越大图像越糊暗色底图可以适当降到 4亮色风景图建议提高到 12。-colorize 35表示在整张图上叠加 35% 不透明度的黑色如果图片本身偏亮可以提到 50偏暗则降到 25。为什么不建议用 CSS 里的filter: blur()因为 GNOME Shell 主题引擎对滤镜支持在不同版本表现不一致而且每个像素都实时做高斯计算登录时的 GPU 占用会偏高。用 convert 预处理后的图就是一张已经模糊好的位图CSS 里不需要任何滤镜逻辑。4.2 每日轮换背景systemd timer 而不是 cron如果我打算让登录背景每天换一张第一反应是写 cron 任务。实际踩过坑后会发现cron 环境里的 PATH 极简convert和glib-compile-resources经常找不到而且脚本报错时日志分散在邮件和 syslog 里排查成本高。用 systemd service 加 timer 是更可控的做法。# /etc/systemd/system/login-background.service [Unit] DescriptionUpdate GDM login background [Service] Typeoneshot ExecStart/usr/local/sbin/set-login-background.sh /data/wallpapers/current.jpg EnvironmentPATH/usr/local/sbin:/usr/bin:/bin# /etc/systemd/system/login-background.timer [Unit] DescriptionRotate login background daily [Timer] OnCalendardaily Persistenttrue [Install] WantedBytimers.target用法上只需要把 service 里的图片路径换成符号链接或固定文件。配合轮换逻辑可以在调用前用shuf从目录里随机挑一张WALLPAPER_DIR/data/wallpapers CURRENT_IMG$(find $WALLPAPER_DIR -type f \( -name *.jpg -o -name *.png \) | shuf -n 1) /usr/local/sbin/set-login-background.sh $CURRENT_IMG需要注意图片体积。脚本会把图片原样嵌进 gresource图片越大重编译越慢GDM 读取主题包时也会变慢。轮换目录里的图片建议统一压缩到 1MB 以内。我试过放一张 8K 原图进去系统启动时登录界面明显等待了几秒才渲染出来换成压缩后的 JPG 后问题消失。4.3 批量装机配合 cloud-init 跑无交互脚本给一批机器统一换登录背景典型的做法是把脚本放到/usr/local/sbin通过 cloud-init 的runcmd在首次开机时执行一次。# cloud-init user-data片段 runcmd: - install -m 0755 /tmp/set-login-background.sh /usr/local/sbin/set-login-background.sh - /usr/local/sbin/set-login-background.sh /tmp/company-login.jpg脚本内部已经包含 root 检查runcmd本身以 root 运行所以直接执行没有问题。需要注意两个边界第一如果目标机器不是 GDM3 而是 LightDM 或 SDDM脚本会直接退出需要在 cloud-init 里先判断显示管理器类型再决定是否调用第二apt upgrade更新 gnome-shell 时会把 gresource 覆盖回默认值批量装机场景里可以在 apt 的 postinst 钩子里追加重跑脚本但这种做法会让升级流程变得脆弱我更倾向在每个季度例维护时统一重跑一次。4.4 图片目录规范把参数固定下来脚本只读一个入口脚本写好后真正省心的是把输入参数固定化。我的习惯是在/etc/login-background/目录下放一张固定名字的current.jpg脚本不接收命令行图片路径只读这个固定文件。轮换流程变成两步替换/etc/login-background/current.jpg然后重跑脚本。这样一个目录把原始图片、脚本、备份文件都收敛在一起排查问题时不用到处找。同时在看效果前先用小图测试编译流程比如先传一张 800x450 的缩略图验证 CSS 注入是否生效确认没问题后再换正式图能避免把大图嵌进去后才发现规则写错。5. 避坑排查修改登录背景时的 5 个常见翻车现场5.1 脚本跑完登录背景纹丝不动现象脚本执行成功重启 GDM登录界面还是默认背景。这个坑我见过最多原因集中在两类一是改错了文件修改的是/usr/share/gnome-shell/gnome-shell.css而不是 gresource 内的那份 CSS二是只改了用户壁纸的gsettings配置GDM 进程根本不读那个配置。解决方法是先做诊断用gresource list查看资源包内的文件列表确认background.png是否还在包里再用gresource extract把 CSS 拉出来搜索#lockDialogGroup看自定义规则是否真的写进去了。如果规则存在但界面没变十有八九是没有重启 GDMsystemctl restart gdm这一步不能省。5.2 登录界面黑屏或紫屏只剩鼠标指针现象重启 GDM 后登录界面渲染异常背景纯黑或纯紫只剩鼠标指针可以动。原因通常是重编译后的 gresource 与 XML 描述不匹配或者 CSS 里写了 GNOME Shell 不支持的属性导致主题解析中断。这时候不要慌直接恢复备份cp /usr/share/gnome-shell/gnome-shell-theme.gresource.bak.时间戳 /usr/share/gnome-shell/gnome-shell-theme.gresource systemctl restart gdm。如果连备份都没有只能apt reinstall gnome-shell但这样会把整个 GNOME Shell 主题重置回默认状态属于最后手段。这个经历给我的教训是每次改动前先备份测试阶段不要连续重启两次至少间隔几分钟观察是否稳定。5.3 背景图比例不对Logo 被裁掉一块现象图片放到登录界面后正中间的 Logo 或公司标识被裁掉或者图片明显变形。原因是对background-size: cover的误解。cover 会等比缩放图片不会拉伸但缩放后超出屏幕的部分会被裁掉。如果源图是竖屏或非常规比例裁掉的内容可能正好是主体。解决方法是把裁切动作放在 ImageMagick 阶段先按目标屏幕分辨率裁好再交给脚本convert source.png -auto-orient -gravity center \ -resize 2560x1440^ -extent 2560x1440 theme/background.png多显示器环境以主显示器的分辨率为准。另外一个容易被忽略的细节是透明 PNG透明区域在 GDM 上会显示黑色底色如果设计稿要求白底必须先在 convert 阶段垫一层白底再输出 JPG。5.4 gnome-shell 更新后自定义背景消失现象系统提示安全更新后登录背景突然变回默认紫红色。原因是 gnome-shell 包更新时会整体替换/usr/share/gnome-shell/gnome-shell-theme.gresource自定义版本被覆盖。解决方法是把脚本放到/usr/local/sbin更新后重跑一次。如果不想每次都手动执行可以借助 apt 的 postinst 钩子在 gnome-shell 更新后自动触发脚本。我在生产环境里更倾向用 systemd path 单元监听 gresource 文件的 mtime文件变化后自动重跑但要注意避免循环触发实测中 apt 更新时可能连续触发多次所以只监听文件变更而不做去重容易收到重复告警。综合下来最简单可靠的方式仍然是在月度维护计划里加一项更新后重跑登录背景脚本。5.5 桌面壁纸变了登录界面没变确认你的显示管理器现象同一套操作在一台机器上生效另一台机器完全不生效。原因往往不是脚本问题而是目标机器用的不是 GDM3。Ubuntu 22.04 默认 GDM3但如果你曾经装过 KDE 或 Xfce并手动切换过显示管理器登录界面就可能由 LightDM 或 SDDM 接管完全不在本文这套机制范围内。解决方法是先确认cat /etc/X11/default-display-manager输出是/usr/sbin/gdm3就继续走这套脚本如果是/usr/sbin/lightdm需要改/etc/lightdm/lightdm-gtk-greeter.conf里的背景配置如果是 SDDM则需要配置对应的主题文件。我在一台改装过 SDDM 的机器上跑过这套脚本结果是白忙一场。针对这个场景我在脚本开头加了一行判断grep -q gdm3 /etc/X11/default-display-manager || exit 2不是 GDM3 就明确退出而不是执行到一半才发现路径不对。6. 验证与回滚给脚本留好后悔药6.1 用 gresource list 验证资源确实被替换脚本跑完后不要急着重启先做一次非破坏性验证。gresource list能直接看到资源包内部的路径列表确认自定义背景图和注入的 CSS 都在里面gresource list /usr/share/gnome-shell/gnome-shell-theme.gresource | grep -E background|gnome-shell.css如果输出里能看到自定义的background.png并且 CSS 文件存在说明重编译和安装成功。登录界面的最终视觉效果只能靠肉眼确认有一个取巧的办法在 GDM 登录界面按 CtrlAltF2 切到字符终端再切回图形界面时可以直接看到背景不用反复重启 GDM。如果屏幕分辨率较高可以先拍一张照片用来肉眼对比颜色和裁切位置是否恰当。6.2 一键回滚从备份恢复原主题脚本里我会额外留一个--revert参数实现从最新备份恢复BACKUP_FILE$(ls -t /usr/share/gnome-shell/gnome-shell-theme.gresource.bak.* 2/dev/null | head -n 1) if [[ -n $BACKUP_FILE ]]; then cp $BACKUP_FILE $THEME_GRESOURCE systemctl restart gdm fi这步代码不多但意义很大。有了回滚入口批量装机时即使背景做坏了远程维护人员也能第一时间恢复而不是让用户对着黑屏界面干等。回滚后建议再执行一次gresource list确认资源包完整尤其是内核升级后 GDM 自动重启的场景。回看这些年改登录背景的经历最值钱的教训不是那条 CSS 规则而是“任何对系统组件的写入都要预留退路”。我最初给客户机器改背景时忘了备份原文件结果登录界面一度黑屏只能靠重新安装救回来。从那以后我所有脚本的第一行永远是备份第二行才是检查参数。希望帮到你。本文还有配套的精品资源点击获取