第 5 章:自定义菜单项
第 5 章:自定义菜单项
5.1 为什么需要自定义菜单
虽然 grub-mkconfig 可以自动检测大多数操作系统,但以下场景需要手动添加菜单项:
- 引导 Windows(os-prober 偶尔失灵)
- 引导 USB Live 系统
- 引导特定内核版本(编译的自定义内核)
- 引导其他发行版的 ISO 镜像
- 链式加载其他引导加载程序
- 故障恢复时手动指定引导参数
5.2 自定义菜单项的位置
5.2.1 方法一:/etc/grub.d/40_custom(推荐)
这是官方推荐的自定义方式,文件内容在 update-grub 时不会被覆盖。
#!/bin/sh
exec tail -n +3 $0
# 此行以上的部分不会出现在 grub.cfg 中
# 你的自定义菜单项从这里开始
menuentry "My Custom Entry" {
...
}
5.2.2 方法二:/boot/grub/custom.cfg
通过 41_custom 加载,无需修改 40_custom:
# 创建或编辑文件
$ sudo nano /boot/grub/custom.cfg
# 添加菜单项
menuentry "Rescue System" {
...
}
⚠️ 注意:
custom.cfg不会参与update-grub流程,直接写入/boot/grub/,适合快速测试。
5.2.3 方法三:GRUB Shell 临时引导
不修改任何文件,在 GRUB 启动时按 c 进入命令行,手动输入引导命令。详见第 8 章。
5.3 引导 Windows
5.3.1 UEFI 模式引导 Windows
menuentry "Windows 11" --class windows --class os --unrestricted {
# 加载分区模块
insmod part_gpt
insmod fat
# 设置 Windows EFI 分区(通常是第一个分区)
# 使用 UUID 更可靠(通过 blkid 获取)
search --no-floppy --fs-uuid --set=root XXXX-XXXX
# 链式加载 Windows Boot Manager
chainloader /EFI/Microsoft/Boot/bootmgfw.efi
}
查找 Windows EFI 分区的 UUID:
$ sudo blkid | grep -i fat
/dev/sda1: UUID="ABCD-1234" TYPE="vfat" PARTLABEL="EFI" PARTUUID="xxxx-xxxx-xxxx"
# 或者更精确地查找 Windows EFI
$ sudo blkid | grep "PARTLABEL=\"EFI system partition\""
5.3.2 Legacy BIOS 模式引导 Windows
menuentry "Windows 10 (Legacy)" --class windows --class os {
insmod part_msdos
insmod ntfs
insmod ntldr
# Windows 安装在第一个分区
set root='hd0,msdos1'
# 方式一:通过 bootmgr 链式加载
chainloader +1
# 方式二:直接加载 bootmgr(推荐)
# ntldr /bootmgr
}
5.3.3 Windows 在不同磁盘上
# Windows 在第二块磁盘的 EFI 分区
menuentry "Windows 11 (Disk 2)" --class windows {
insmod part_gpt
insmod fat
search --no-floppy --fs-uuid --set=root YYYY-YYYY
chainloader /EFI/Microsoft/Boot/bootmgfw.efi
}
5.4 引导其他 Linux 发行版
5.4.1 引导其他磁盘上的 Linux
menuentry "Ubuntu 24.04 on /dev/sdb2" --class gnu-linux {
insmod part_gpt
insmod ext2
# 设置目标 Linux 的 /boot 分区
set root='hd1,gpt2'
# 使用 UUID 更可靠
search --no-floppy --fs-uuid --set=root yyyy-yyyy-yyyy
# 加载内核和 initramfs
linux /vmlinuz root=UUID=zzzz-zzzz-zzzz ro quiet
initrd /initrd.img
}
5.4.2 从 ISO 文件引导
这是一个非常实用的功能,可以直接从 ISO 镜像引导 Live 系统。
引导 Ubuntu ISO:
menuentry "Ubuntu 24.04 Live ISO" {
insmod loopback
insmod iso9660
insmod part_gpt
insmod ext2
# ISO 文件所在的分区
set root='hd0,gpt4'
# 挂载 ISO 为回环设备
loopback loop /iso/ubuntu-24.04-desktop-amd64.iso
# 从 ISO 中加载内核
linux (loop)/casper/vmlinuz boot=casper iso-scan/filename=/iso/ubuntu-24.04-desktop-amd64.iso quiet splash
initrd (loop)/casper/initrd
}
引导 Debian ISO:
menuentry "Debian 12 Netinst ISO" {
insmod loopback
insmod part_gpt
insmod ext2
set root='hd0,gpt4'
loopback loop /iso/debian-12-amd64-netinst.iso
linux (loop)/install.amd/vmlinuz iso-scan/filename=/iso/debian-12-amd64-netinst.iso
initrd (loop)/install.amd/initrd.gz
}
引导 Fedora ISO:
menuentry "Fedora 39 Workstation ISO" {
insmod loopback
insmod part_gpt
insmod ext2
set root='hd0,gpt4'
loopback loop /iso/Fedora-Workstation-Live-x86_64-39-1.5.iso
linux (loop)/images/pxeboot/vmlinuz root=live:CDLABEL=Fedora-WS-Live-39-1-5 iso-scan/filename=/iso/Fedora-Workstation-Live-x86_64-39-1.5.iso
initrd (loop)/images/pxeboot/initrd.img
}
⚠️ 注意:ISO 引导的内核参数因发行版而异,需要参考各发行版的文档。ISO 文件需要存放在 GRUB 可识别的文件系统分区上。
5.4.3 引导自定义编译的内核
menuentry "Custom Kernel 6.8.0-custom" {
insmod part_gpt
insmod ext2
set root='hd0,gpt2'
linux /vmlinuz-6.8.0-custom root=UUID=xxx ro quiet
initrd /initrd.img-6.8.0-custom
}
5.5 链式加载(Chainloading)
链式加载是将引导控制权交给另一个引导加载程序的技术。
5.5.1 链式加载的工作原理
GRUB2 → chainloader 命令 → 目标引导程序 → 操作系统
chainloader 命令将指定位置的代码加载到内存并执行,相当于"转交引导权"。
5.5.2 链式加载 EFI 程序
# 链式加载任何 EFI 程序
menuentry "EFI Shell" {
insmod part_gpt
insmod fat
set root='hd0,gpt1'
chainloader /EFI/tools/shell.efi
}
# 链式加载另一个 GRUB
menuentry "Another GRUB Installation" {
insmod part_gpt
insmod fat
set root='hd0,gpt1'
chainloader /EFI/ubuntu/grubx64.efi
}
# 链式加载 rEFInd
menuentry "rEFInd Boot Manager" {
insmod part_gpt
insmod fat
set root='hd0,gpt1'
chainloader /EFI/refind/refind_x64.efi
}
5.5.3 链式加载 MBR(Legacy BIOS)
# 从第二块磁盘的 MBR 链式加载
menuentry "Boot from second disk" {
set root=(hd1)
chainloader +1 # +1 表示加载第一个扇区(MBR)
}
# 从分区的引导扇区链式加载
menuentry "Boot partition /dev/sdb1" {
set root=(hd1,msdos1)
chainloader +1
}
5.6 引导 ISO 镜像的进阶技巧
5.6.1 通用 ISO 引导模板
menuentry "Boot ISO: <ISO名称>" {
# 1. 加载必要模块
insmod loopback
insmod part_gpt
insmod ext2
# 2. 设置 ISO 文件所在分区
search --set=root --file /iso/<文件名>.iso
# 3. 创建回环设备
loopback loop /iso/<文件名>.iso
# 4. 从 ISO 加载内核(路径因发行版而异)
linux (loop)/<内核路径> <引导参数>
initrd (loop)/<initrd路径>
}
5.6.2 Memdisk 引导 ISO(BIOS 模式)
对于某些小 ISO,可以使用 memdisk 将整个 ISO 加载到内存:
menuentry "Hiren's BootCD" {
insmod part_msdos
insmod fat
set root='hd0,msdos1'
linux16 /memdisk iso
initrd16 /HBCD_PE_x64.iso
}
⚠️ 注意:memdisk 方式会将整个 ISO 加载到 RAM,ISO 文件不能太大(建议 < 2GB),且需要足够内存。
5.7 高级菜单组织
5.7.1 使用 submenu 组织菜单
submenu "Tools and Utilities" --class tools {
menuentry "Memtest86+" {
insmod part_gpt
insmod ext2
set root='hd0,gpt2'
linux /boot/memtest86+x64.bin
}
menuentry "SystemRescue" {
insmod part_gpt
insmod ext2
search --set=root --file /iso/systemrescue.iso
loopback loop /iso/systemrescue.iso
linux (loop)/sysresccd/boot/x86_64/vmlinuz archisobasedir=sysresccd img_label=SYSRES img_loop=/iso/systemrescue.iso
initrd (loop)/sysresccd/boot/x86_64/sysresccd.img
}
menuentry "GParted Live" {
insmod loopback
insmod part_gpt
insmod ext2
set root='hd0,gpt4'
loopback loop /iso/gparted-live.iso
linux (loop)/live/vmlinuz boot=live components config quiet
initrd (loop)/live/initrd.img
}
}
5.7.2 使用 hotkey 设置快捷键
menuentry "Windows" --hotkey='w' --class windows {
chainloader /EFI/Microsoft/Boot/bootmgfw.efi
}
menuentry "Ubuntu" --hotkey='u' --class gnu-linux {
linux /boot/vmlinuz root=UUID=xxx ro
initrd /boot/initrd.img
}
5.7.3 密码保护特定菜单项
# 在 /etc/grub.d/40_custom 中
# 需要先在 /etc/grub.d/00_header 或 40_custom 中设置密码
menuentry "Admin Recovery" --users admin {
insmod part_gpt
insmod ext2
set root='hd0,gpt2'
linux /boot/vmlinuz root=UUID=xxx ro single
initrd /boot/initrd.img
}
5.8 完整自定义示例
以下是一个完整的 /etc/grub.d/40_custom 示例:
#!/bin/sh
exec tail -n +3 $0
# ==================================================
# Windows 引导
# ==================================================
menuentry "Windows 11" --class windows --class os --unrestricted {
insmod part_gpt
insmod fat
search --no-floppy --fs-uuid --set=root ABCD-1234
chainloader /EFI/Microsoft/Boot/bootmgfw.efi
}
# ==================================================
# Ubuntu 24.04 ISO
# ==================================================
menuentry "Ubuntu 24.04 Desktop ISO" --class ubuntu {
insmod loopback
insmod part_gpt
insmod ext2
search --no-floppy --fs-uuid --set=root 1111-2222-3333
loopback loop /iso/ubuntu-24.04-desktop-amd64.iso
linux (loop)/casper/vmlinuz boot=casper iso-scan/filename=/iso/ubuntu-24.04-desktop-amd64.iso quiet splash
initrd (loop)/casper/initrd
}
# ==================================================
# 子菜单:工具
# ==================================================
submenu "System Tools" --class tools {
menuentry "Memtest86+" {
insmod part_gpt
insmod ext2
set root='hd0,gpt2'
linux /boot/memtest86+x64.bin
}
menuentry "EFI Shell" {
insmod part_gpt
insmod fat
set root='hd0,gpt1'
chainloader /EFI/tools/shell.efi
}
}
5.9 GRUB 模块参考
自定义菜单项时可能需要加载各种模块:
| 模块 | 用途 |
|---|---|
part_gpt | GPT 分区表支持 |
part_msdos | MBR 分区表支持 |
ext2 | ext2/3/4 文件系统支持 |
fat | FAT12/16/32 文件系统支持 |
ntfs | NTFS 文件系统支持 |
iso9660 | ISO 9660(CD-ROM)文件系统支持 |
loopback | 回环设备支持(挂载 ISO) |
chainloader | 链式加载支持 |
search | 搜索分区/文件 |
linux | Linux 内核加载 |
all_video | 所有视频驱动 |
gzio | gzip 解压(用于压缩的内核/initrd) |
test | 条件测试命令 |
lsefi | 列出 EFI 系统信息(仅 UEFI) |
lspci | 列出 PCI 设备 |
btrfs | Btrfs 文件系统支持 |
xfs | XFS 文件系统支持 |
zfs | ZFS 文件系统支持 |
检查模块是否可用
# 在 GRUB Shell 中
grub> insmod part_gpt
# 如果无输出,说明加载成功
# 如果报错 "unknown filesystem",说明模块不存在
# 列出可用模块
grub> ls /boot/grub/x86_64-efi/
5.10 扩展阅读
上一章:第 4 章:自动生成配置 | 下一章:第 6 章:主题与美化