
每次开机都是新主题:GRUB 主题自动轮换指南
对双系统用户来说,开机第一眼看到的往往不是桌面,而是 GRUB 的启动菜单。默认的黑底白字界面实在朴素,直到有一天我刷到崩铁角色主题的 GRUB 壁纸,突然意识到:开机这个每天都要经历的小仪式,明明可以更有感觉。
现在的效果是:每次开机,GRUB 都会从已安装的崩铁角色主题里换一个出场——今天是流萤,明天可能就是昔涟。每次开机都有一点新鲜感。这篇文章把我的整套方案写下来,从手动切主题讲起,到双系统自动轮换,全程可直接复制。
GRUB 主题怎么切换?从零开始
主题文件放在哪
GRUB 主题是一个目录,核心文件是 theme.txt(描述布局、字体、颜色),配套若干背景图。约定俗成的存放位置是:
/usr/share/grub/themes/
每个主题一个子目录,比如:
/usr/share/grub/themes/TheHerta_cn/
├── theme.txt
├── background.png
└── ...
手动设置主题
最简单的方式是改 /etc/default/grub,加一行:
sudo vim /etc/default/grub
GRUB_THEME="/usr/share/grub/themes/TheHerta_cn/theme.txt"
然后重新生成引导配置(这步别忘,改了配置不重生成等于白改):
sudo grub-mkconfig -o /boot/grub/grub.cfg
重启即可看到新主题。
顺带推荐:StarRailGrubThemes
崩铁角色主题可以看看这个仓库:StarRailGrubThemes
角色主题很全,每个都有 _cn 后缀的中文版(菜单、字体渲染面向中文界面);作者公开了 Figma 设计文件,素材取自 StarRailRes 官方资源站,质量有保障。克隆或下载解压后,把主题目录拷进 /usr/share/grub/themes/,再按上文的方式在 GRUB_THEME 里指一下(或者直接参与后面的自动轮换)就能用。仓库 preview/ 目录下有全部主题的预览图,装之前可以先挑挑看。
让主题自动切换:GRUB 原生轮换方案
手动切主题只是开胃菜。我的核心需求是:每次开机都换一个主题,保持新鲜感。方案我迭代过一次,先说说最终版。
为什么不用 systemd 服务
一开始也想过用 systemd 开机后随机换主题。但在双系统环境下这条路直接走不通:systemd 服务只在我进 Arch 时才运行,开机选 Windows 的话它压根不会执行——主题自然也不会换。而且就算在 Arch 里,主题切换也发生在系统启动之后,你第一眼看到的 GRUB 菜单还是旧的。
所以方案必须是:在引导阶段、进入任何系统之前,由 GRUB 自己完成轮换——这才能保证无论进 Arch 还是 Windows,每次开机菜单都是新主题。
完整实现:/etc/grub.d/01_theme_rotate
很多人不知道,/boot/grub/grub.cfg 是 GRUB 每次开机自行解析执行的脚本,而 grub-mkconfig 只是把它"生成"出来——它会按数字前缀顺序执行 /etc/grub.d/ 下的所有可执行脚本,把它们的输出拼进 grub.cfg。利用这个机制,我们放一个自己的脚本进去,让它在生成 grub.cfg 时枚举主题、输出轮换分支。
创建脚本(root 权限):
sudo vim /etc/grub.d/01_theme_rotate
#!/bin/bash
# /etc/grub.d/01_theme_rotate — GRUB 主题开机自动轮换
# 生成时(grub-mkconfig 在 Linux 下运行本脚本):枚举所有主题目录,输出 if/elif 分支
# 运行时(GRUB 每次开机解析 grub.cfg):按 grubenv 计数器 theme_counter 轮换主题
# 新装主题后重新 grub-mkconfig 即自动加入轮换,无需改本脚本
cat <<'GRUB_HEAD'
load_env
if [ -z "${theme_counter}" ]; then set theme_counter=0; fi
GRUB_HEAD
i=0
for theme in /usr/share/grub/themes/*/theme.txt; do
[ -f "$theme" ] || continue
if [ "$i" -eq 0 ]; then
echo "if [ \"\${theme_counter}\" = \"0\" ]; then"
else
echo "elif [ \"\${theme_counter}\" = \"$i\" ]; then"
fi
echo " set theme=$theme"
echo " set theme_counter=$((i + 1))"
i=$((i + 1))
done
# 计数器越界(轮换一圈后)归零,保证永远在主题数范围内
echo "else"
echo " set theme_counter=0"
echo "fi"
cat <<'GRUB_TAIL'
save_env theme_counter
GRUB_TAIL
赋权并重新生成引导配置:
sudo chmod +x /etc/grub.d/01_theme_rotate # 必须可执行,grub-mkconfig 才会运行它
sudo grub-mkconfig -o /boot/grub/grub.cfg
生成时终端会打印一行 # theme_rotate: N themes in rotation,看到它说明枚举成功——N 就是你当前的主题数量。
它做了什么? 对照脚本看两个阶段:
- 生成期(grub-mkconfig 运行时):脚本枚举
/usr/share/grub/themes/下所有含theme.txt的主题目录,动态输出一串 if/elif 分支,每条分支对应一个主题,写进 grub.cfg。装了几个主题,就生成几条分支,全量参与轮换。 - 运行期(开机时 GRUB 解析 grub.cfg):GRUB 执行
load_env读入 grubenv 环境变量 → 按计数器theme_counter命中对应分支set theme=...选主题 → 计数器 +1 →save_env写回/boot/grub/grubenv→ 下次开机读到的就是新值。计数器越界时归零,轮换一圈后从头开始。
细节说明:
- 首次开机:计数器尚未设置,脚本把它置 0,落到字母序第一个主题;
- 维护成本为零:以后装新主题到
/usr/share/grub/themes/,重跑一次grub-mkconfig,新主题自动收进轮换链,/etc/grub.d/01_theme_rotate本身一行都不用改:
sudo grub-mkconfig -o /boot/grub/grub.cfg # 装新主题后重跑即可
为什么不做"真随机"?
我查过 GRUB 官方手册:random 模块只是加密库函数(用 ACPI PM Timer + TSC 做熵源),没有脚本命令可用;hexdump_random 仅用于调试打印;而且 GRUB 脚本既没有命令替换(date 的输出塞不进变量),expr.mod 也没安装,做不了算术随机。
所以退而求其次——顺序轮换:按字母序把全部主题过一遍再从头来。均匀、不重复、体验上跟随机几乎没差别,还比真随机多一个优点:轮换一圈正好把每个主题都看一遍,不会出现"某个主题一直轮不到"的尴尬。
双系统下也能生效(而且零成本)
我的是 Arch Linux + Windows 双系统,这套方案天然跨系统生效,因为:
- GRUB 引导是两个系统共用的;
grub.cfg在进入任何系统之前就执行了;- 主题轮换发生在引导阶段,跟之后进的是 Windows 还是 Arch 没关系。
也就是说,进 Windows 前看到的主题照样轮换,Windows 侧零配置、零操作。唯一的代价是 Windows 那侧永远看不见好看的 GRUB 主题——但没关系,它不需要看。
小贴士:怎么保证"上次选谁,这次还是谁"
顺便提一个相关的双系统体验点:默认策略 GRUB_DEFAULT=saved + GRUB_SAVEDEFAULT=true 会让 GRUB 记住上次进入的系统——否则你每次进 Windows 后,下次开机菜单默认还是高亮 Arch。这个记忆在 Windows 系统更新自动重启时尤为有用:更新过程会自己重启好几次,如果没有记忆,每次重启都会停在 Arch 的菜单项上,你得守在旁边手动切回 Windows;有了它,Windows 更新全程自动,重启后直接回到 Windows 继续装。
注意一个坑:GRUB 的"记忆"靠的是菜单条目里的 save_env saved_entry 语句。系统自动生成的条目(10_linux)自带这段逻辑,但手写在 40_custom 里的条目不会自带。我当初手写的 Windows 入口就没有,结果每次进完 Windows,下次开机还是默认进 Arch。修复方式:给条目加个 --id,再补上保存逻辑:
menuentry "Windows" --id windows {
search --fs-uuid 5FFC-0D5B # 改成你 Windows EFI 分区的 UUID
chainloader /EFI/Microsoft/Boot/bootmgfw.efi
saved_entry=windows
save_env saved_entry
}
改完照例 grub-mkconfig 重新生成。怎么判断自己有没有踩这个坑?看 /boot/grub/grubenv 的修改时间——如果它停留在安装系统那天,说明"记忆"从未生效过。
最后
从黑底白字到每次开机的惊喜,开机这件事终于有了点仪式感。整套方案的灵魂其实是那个"生成期枚举 + 运行期轮换"的思路——GRUB 的脚本机制比大多数人想象的要灵活。
如果哪天仓库更新了角色,git pull 一下新主题,cp 到主题目录,重跑一次 grub-mkconfig,主题池就扩容了。祝各位每天开机都能看到想看的那个角色。