强曰为道
与天地相似,故不违。知周乎万物,而道济天下,故不过。旁行而不流,乐天知命,故不忧.
文档目录

GRUB2 引导管理器完全教程 / 第 4 章:自动生成配置

第 4 章:自动生成配置

4.1 grub-mkconfig 概述

grub-mkconfig 是 GRUB2 的配置生成工具,它扫描系统中已安装的内核和其他操作系统,自动生成 /boot/grub/grub.cfg 文件。在 Debian/Ubuntu 系统中,update-grubgrub-mkconfig 的一个封装脚本。

4.1.1 基本用法

# Debian/Ubuntu(封装命令)
$ sudo update-grub

# 等效于
$ sudo grub-mkconfig -o /boot/grub/grub.cfg

# RHEL/CentOS/Fedora
$ sudo grub2-mkconfig -o /boot/grub2/grub.cfg

# Arch Linux
$ sudo grub-mkconfig -o /boot/grub/grub.cfg

4.1.2 查看输出而不写入

# 将生成的配置输出到标准输出(不写文件)
$ sudo grub-mkconfig

这在调试时非常有用,可以检查生成的配置是否正确,而不影响当前的 grub.cfg。

4.1.3 工作流程

grub-mkconfig 执行流程:

1. 加载 /etc/default/grub 中的变量
2. 运行 /etc/grub.d/ 下所有可执行脚本(按文件名排序)
3. 各脚本输出菜单项片段到 stdout
4. 所有输出合并写入 grub.cfg
/etc/default/grub       ← 用户配置变量
        │
        ▼
┌──────────────────────────────┐
│ /etc/grub.d/                 │
│  ├── 00_header      ───────────── 超时、默认项、主题
│  ├── 05_debian_theme ──────────── 背景、颜色
│  ├── 10_linux       ───────────── Linux 内核
│  ├── 20_linux_xen   ───────────── Xen 虚拟化
│  ├── 30_os-prober   ───────────── 其他操作系统
│  ├── 30_uefi-firmware ─────────── UEFI 固件入口
│  ├── 40_custom      ───────────── 用户自定义菜单
│  └── 41_custom      ───────────── 额外自定义配置
└──────────────────────────────┘
        │
        ▼
/boot/grub/grub.cfg     ← 生成的最终配置

4.2 /etc/grub.d/ 脚本详解

4.2.1 脚本命名规则

脚本按文件名的字母顺序执行。命名约定:

前缀含义
00-09GRUB 头部设置
10-19主要操作系统条目
20-29辅助操作系统条目
30-39其他操作系统探测
40-49用户自定义
90-99尾部(如 90_persistent

4.2.2 控制脚本是否执行

# 方法一:移除可执行权限
$ sudo chmod -x /etc/grub.d/30_os-prober  # 禁用 os-prober

# 方法二:添加 .disabled 后缀
$ sudo mv /etc/grub.d/30_os-prober /etc/grub.d/30_os-prober.disabled

# 恢复
$ sudo chmod +x /etc/grub.d/30_os-prober

4.2.3 00_header — 头部配置

00_header 脚本负责读取 /etc/default/grub 中的变量,生成 grub.cfg 的头部:

# 生成的内容包括:
# - set default=...
# - set timeout=...
# - set timeout_style=...
# - loadfont ...
# - insmod ...
# - set gfxmode=...
# - terminal_output gfxterm
# - 主题设置
# - background_image

4.2.4 10_linux — Linux 内核检测

10_linux 脚本是核心脚本,负责检测 /boot 目录中的内核文件并生成菜单项。

检测逻辑:

# 扫描以下目录中的内核文件
/boot/vmlinuz-*
/boot/vmlinuz
/boot/kernel-*
/boot/bzImage-*

# 匹配的 initramfs 文件
/boot/initrd.img-*
/boot/initramfs-*.img
/boot/initramfs-*

生成的菜单项:

# 正常启动项
menuentry 'Debian GNU/Linux' --class debian --class gnu-linux --class gnu --class os {
    ...
    linux /boot/vmlinuz-6.1.0-amd64 root=UUID=xxx ro quiet
    initrd /boot/initrd.img-6.1.0-amd64
}

# 恢复模式项(如果未禁用)
menuentry 'Debian GNU/Linux (recovery mode)' --class debian {
    ...
    linux /boot/vmlinuz-6.1.0-amd64 root=UUID=xxx ro single
    initrd /boot/initrd.img-6.1.0-amd64
}

4.2.5 20_linux_xen — Xen 虚拟化

检测 Xen hypervisor 并生成对应的菜单项。大多数桌面用户不需要此脚本。

# 如果不使用 Xen,可以禁用
$ sudo chmod -x /etc/grub.d/20_linux_xen

4.2.6 30_os-prober — 检测其他操作系统

30_os-prober 脚本调用 os-prober 工具检测磁盘上安装的其他操作系统。

支持检测的系统:

系统检测方式
Windows检测 bootmgr / BCD
其他 Linux检测内核文件和 initramfs
macOS检测 HFS+ 分区
BSD检测引导加载程序

启用 os-prober:

# 1. 安装 os-prober
$ sudo apt install os-prober  # Debian/Ubuntu
$ sudo dnf install os-prober   # RHEL/Fedora

# 2. 确保 /etc/default/grub 中未禁用
# GRUB_DISABLE_OS_PROBER=false(默认值)

# 3. 重新生成配置
$ sudo update-grub

⚠️ 注意:从 Ubuntu 22.04 和 Debian 12 开始,GRUB_DISABLE_OS_PROBER 默认为 true(出于安全考虑),需要手动设为 false 并安装 os-prober

os-prober 安全提示:

os-prober 需要挂载其他分区来检测操作系统,这在某些安全敏感场景下可能存在风险。如果系统不需要多系统引导,建议保持禁用。

4.2.7 30_uefi-firmware — UEFI 固件入口

在 UEFI 系统上生成一个菜单项,允许直接进入 UEFI 固件设置界面:

menuentry 'System setup' --unrestricted {
    fwsetup
}

4.2.8 40_custom — 用户自定义

40_custom 是用户添加自定义菜单项的标准位置。该文件不会被 update-grub 覆盖。

#!/bin/sh
exec tail -n +3 $0
# 该行以上的内容不会出现在 grub.cfg 中

# 自定义菜单项示例:引导 Windows
menuentry "Windows 11" --class windows --class os {
    insmod part_gpt
    insmod fat
    search --no-floppy --fs-uuid --set=root XXXX-XXXX
    chainloader /EFI/Microsoft/Boot/bootmgfw.efi
}

# 自定义菜单项:旧内核
menuentry "Linux 5.10 (旧内核)" {
    insmod part_gpt
    insmod ext2
    set root='hd0,gpt2'
    linux /boot/vmlinuz-5.10.0-amd64 root=UUID=xxx ro
    initrd /boot/initrd.img-5.10.0-amd64
}

⚠️ 注意exec tail -n +3 $0 这一行的作用是跳过脚本本身的前 3 行(#!/bin/shexec tail、和空行),直接输出后续内容到 grub.cfg。

4.2.9 41_custom — 补充自定义配置

41_custom 加载 /boot/grub/custom.cfg 文件(如果存在),适合在不修改 40_custom 的情况下添加额外菜单:

#!/bin/sh
echo "source /boot/grub/custom.cfg"

然后创建 /boot/grub/custom.cfg

# /boot/grub/custom.cfg
menuentry "Rescue System" {
    insmod part_gpt
    insmod ext2
    set root='hd0,gpt2'
    linux /boot/rescue/vmlinuz root=UUID=xxx
    initrd /boot/rescue/initrd.img
}

4.3 os-prober 工具详解

4.3.1 os-prober 工作原理

# 手动运行 os-prober
$ sudo os-prober
# /dev/sda1:Windows 10:Windows:chain
# /dev/sda5:Ubuntu 22.04 LTS (22.04):Ubuntu:linux

探测流程:

  1. 扫描所有已挂载的分区
  2. 检查分区上的特征文件(如 /bootmgr/vmlinuz
  3. 识别操作系统类型和版本
  4. 输出设备:名称:类型:引导方式

4.3.2 自定义 os-prober 排除

# 在 /etc/default/grub 中添加排除分区
# GRUB_OS_PROBER_SKIP_LIST="sda1@/dev/sda"

# 或者通过 /etc/os-prober.conf 配置(如果存在)

4.3.3 linux-boot-prober

os-prober 对 Linux 系统的探测依赖 linux-boot-prober,它需要能挂载目标分区并读取内核文件。

# 手动探测特定分区
$ sudo linux-boot-prober /dev/sda5
# /dev/sda5:/boot/vmlinuz-5.15.0:/boot/initrd.img-5.15.0:root=UUID=xxx:ro:

4.4 变量与环境

4.4.1 grub-mkconfig 使用的变量

grub-mkconfig 在执行时会设置以下内部变量:

变量说明来源
GRUB_DEFAULT默认启动项/etc/default/grub
GRUB_TIMEOUT超时时间/etc/default/grub
GRUB_CMDLINE_LINUX_DEFAULT默认内核参数/etc/default/grub
GRUB_CMDLINE_LINUX所有菜单项的内核参数/etc/default/grub
GRUB_TERMINAL终端类型/etc/default/grub
GRUB_THEME主题路径/etc/default/grub
GRUB_GFXMODE图形分辨率/etc/default/grub

4.4.2 传递额外参数给内核

# 在 /etc/default/grub 中
GRUB_CMDLINE_LINUX_DEFAULT="quiet splash"
GRUB_CMDLINE_LINUX="ipv6.disable=1"

# 效果:所有菜单项的内核参数会包含 ipv6.disable=1
# 正常模式:quiet splash ipv6.disable=1
# 恢复模式:single ipv6.disable=1

4.4.3 按菜单项添加参数

如果需要为特定内核添加参数,可以在 /etc/grub.d/10_linux 中添加逻辑,或使用 40_custom 手动定义菜单项。

4.5 高级用法

4.5.1 自定义 10_linux 脚本

在某些场景下,你可能需要修改 10_linux 来改变内核检测逻辑。

示例:在所有内核菜单项中添加额外参数

# 编辑 /etc/grub.d/10_linux
# 找到以下行(大约在第 180-200 行附近):
#   "${GRUB_CMDLINE_LINUX@Q}" "${GRUB_CMDLINE_LINUX_DEFAULT@Q}"
# 可以在函数调用处添加额外参数

# 更好的做法:使用 GRUB_CMDLINE_LINUX
# 在 /etc/default/grub 中:
GRUB_CMDLINE_LINUX="apparmor=1 security=apparmor"

4.5.2 禁用恢复模式菜单项

# 在 /etc/default/grub 中
GRUB_DISABLE_RECOVERY="true"

# 然后重新生成
$ sudo update-grub

4.5.3 禁用子菜单

默认情况下,多个内核版本会被组织到子菜单中:

# 禁用子菜单,所有项平铺显示
GRUB_DISABLE_SUBMENU=true

4.5.4 限制显示的内核数量

方法一:手动移除旧内核

# 查看已安装的内核
$ dpkg --list | grep linux-image

# 移除旧内核(保留当前和一个备用)
$ sudo apt remove linux-image-5.10.0-amd64
$ sudo update-grub

方法二:使用 apt autoremove

$ sudo apt autoremove --purge

方法三:配置 apt 自动清理

# /etc/apt/apt.conf.d/99-autoremove-kernels
# 控制保留的内核数量

4.5.5 预生成配置检查

# 先查看生成的配置内容
$ sudo grub-mkconfig 2>&1 | head -100

# 检查是否有错误
$ sudo grub-mkconfig 2>/tmp/grub-errors.log
$ cat /tmp/grub-errors.log

4.6 发行版差异对照

项目Debian/UbuntuRHEL/FedoraArch Linux
命令update-grubgrub2-mkconfiggrub-mkconfig
配置文件/etc/default/grub/etc/default/grub/etc/default/grub
输出路径/boot/grub/grub.cfg/boot/grub2/grub.cfg/boot/grub/grub.cfg
脚本目录/etc/grub.d//etc/grub.d//etc/grub.d/
环境文件/boot/grub/grubenv/boot/grub2/grubenv/boot/grub/grubenv
持久化默认项GRUB_SAVEDEFAULT=true需配置 grubbyGRUB_SAVEDEFAULT=true

RHEL/Fedora 特殊配置

# RHEL 使用 grubby 管理内核
# 查看默认内核
$ grubby --default-kernel
# /boot/vmlinuz-5.14.0-162.6.1.el9_1.x86_64

# 设置默认内核
$ sudo grubby --set-default /boot/vmlinuz-5.14.0-162.6.1.el9_1.x86_64

# 修改内核参数
$ sudo grubby --update-kernel=ALL --args="ipv6.disable=1"

4.7 调试 grub-mkconfig

4.7.1 常见问题诊断

问题:os-prober 未检测到 Windows

# 1. 确认 os-prober 已安装
$ which os-prober

# 2. 确认 Windows 分区已挂载(os-prober 需要)
$ sudo mount /dev/sda1 /mnt
$ sudo os-prober

# 3. 确认未禁用
$ grep DISABLE_OS_PROBER /etc/default/grub
GRUB_DISABLE_OS_PROBER=false

# 4. 重新生成
$ sudo update-grub

问题:未检测到新安装的内核

# 1. 确认内核文件存在于 /boot
$ ls /boot/vmlinuz-*

# 2. 确认 initramfs 已生成
$ ls /boot/initrd.img-* /boot/initramfs-*

# 3. 如果缺少 initramfs,手动生成
$ sudo update-initramfs -c -k 6.1.0-amd64  # Debian/Ubuntu
$ sudo dracut --force /boot/initramfs-6.1.0.img 6.1.0  # RHEL/Fedora

# 4. 重新生成 grub.cfg
$ sudo update-grub

4.7.2 详细输出

# grub-mkconfig 默认会输出进度信息到 stderr
$ sudo grub-mkconfig -o /boot/grub/grub.cfg 2>&1
# Generating grub configuration file ...
# Found linux image: /boot/vmlinuz-6.1.0-amd64
# Found initrd image: /boot/initrd.img-6.1.0-amd64
# Found Windows Boot Manager on /dev/sda1@/EFI/Microsoft/Boot/bootmgfw.efi
# done

4.8 扩展阅读


上一章:第 3 章:配置文件详解 | 下一章:第 5 章:自定义菜单项