GRUB2 引导管理器:从配置文件到修复实战

GRUB2,全称 GRand Unified Bootloader 2,是目前绝大多数 Linux 发行版的默认引导管理器。说白了,它就是操作系统启动时第一个跑起来的程序,负责把内核加载进内存。我刚开始接触多系统时,总觉得 GRUB2 很神秘,动不动就进不去系统。后来摸透了它的脾气,才发现其实就那几个核心文件在起作用。

核心认知:GRUB2 的配置文件不是手写的,而是由脚本自动生成的。你直接编辑 /boot/grub/grub.cfg ?下次更新内核,改动就全丢了。正确做法是修改 /etc/default/grub 和 /etc/grub.d/ 目录下的脚本。

GRUB2 配置文件结构

GRUB2 的配置体系分三层,我画了张图帮你理清关系:

GRUB2 配置文件结构图 GRUB2 配置文件体系 /boot/grub/grub.cfg (自动生成,不要直接编辑) /etc/grub.d/ 目录下的脚本 00_header → 10_linux → 30_os-prober → 40_custom /etc/default/grub (用户自定义参数,如超时时间、默认系统) 执行顺序 1. 读取 /etc/default/grub 2. 按编号执行脚本 3. 合并生成 grub.cfg 4. 更新后需运行 update-grub

从上图能看出来,grub.cfg 是最终产物。它由 /etc/grub.d/ 里的脚本,结合 /etc/default/grub 里的参数,通过 update-grub 或 grub-mkconfig 命令生成。我个人习惯把 /etc/default/grub 比作「调料配方」,/etc/grub.d/ 里的脚本是「菜谱步骤」,最终炒出来的菜就是 grub.cfg。

grub.cfg 详解

打开 /boot/grub/grub.cfg,你会看到一堆密密麻麻的脚本。别慌,核心结构其实很清晰:

段落 作用 典型内容
头部 加载必要模块,设置全局变量 set default="0"、set timeout=5
菜单项 每个 menuentry 块定义一个启动项 menuentry 'Ubuntu' { ... }
子菜单 用 submenu 包裹高级选项 submenu '高级选项' { ... }
尾部 加载主题、字体等资源 source $prefix/grub.cfg

一个典型的 menuentry 块长这样:

menuentry 'Ubuntu 22.04 LTS' --class ubuntu --class gnu-linux --class gnu --class os $menuentry_id_option 'gnulinux-simple-xxxx' {
    recordfail
    load_video
    gfxmode $linux_gfx_mode
    insmod gzio
    insmod part_gpt
    insmod ext2
    set root='hd0,gpt2'
    search --no-floppy --fs-uuid --set=root xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx
    linux   /vmlinuz-5.15.0-generic root=UUID=yyyyyyyy-yyyy-yyyy-yyyy-yyyyyyyyyyyy ro  quiet splash
    initrd  /initrd.img-5.15.0-generic
}

这里我解释几个关键点:

  • set root:指定根分区,hd0,gpt2 表示第一块硬盘的第二个 GPT 分区
  • search --fs-uuid:通过 UUID 查找分区,比设备名更可靠
  • linux 行:指定内核文件路径和内核参数,ro 表示只读挂载根文件系统
  • initrd 行:指定初始 RAM 磁盘,用于加载必要的驱动

我的经验:UUID 是分区最稳定的标识符。设备名如 /dev/sda1 会随硬盘接口变化而改变,但 UUID 不会。我曾经帮同事修一台服务器,他直接写死了 /dev/sdb2,结果加了一块硬盘后系统就起不来了。换成 UUID 后,再也没出过问题。

自定义启动菜单

想改 GRUB2 菜单?记住一个原则:改配置,别改产物。具体步骤是:

  1. 编辑 /etc/default/grub 设置全局参数
  2. 在 /etc/grub.d/40_custom 中添加自定义菜单项
  3. 运行 update-grub 重新生成 grub.cfg

常用的 /etc/default/grub 参数:

参数 默认值 说明
GRUB_DEFAULT 0 默认启动项,可以是数字或菜单项名称
GRUB_TIMEOUT 5 倒计时秒数,设为 -1 则等待用户选择
GRUB_CMDLINE_LINUX "" 传递给所有 Linux 内核的额外参数
GRUB_DISABLE_OS_PROBER false 是否禁用自动探测其他操作系统
GRUB_GFXMODE auto 图形模式分辨率,如 1920x1080

举个例子,我想让 Windows 10 作为默认启动项,并且把倒计时改成 10 秒:

# 编辑 /etc/default/grub
GRUB_DEFAULT="Windows 10"
GRUB_TIMEOUT=10

# 然后更新
sudo update-grub

如果想添加一个自定义的启动项,比如从 ISO 文件直接启动:

# 编辑 /etc/grub.d/40_custom
menuentry "Live Ubuntu ISO" {
    set isofile="/iso/ubuntu-22.04-desktop-amd64.iso"
    loopback loop $isofile
    linux (loop)/casper/vmlinuz boot=casper iso-scan/filename=$isofile quiet splash
    initrd (loop)/casper/initrd
}

# 更新
sudo update-grub

注意:自定义菜单项的文件名必须以数字开头,比如 40_custom。数字决定了执行顺序,数字越小越先执行。我见过有人把文件命名为 custom,结果 update-grub 直接忽略了它。

修复 GRUB2 引导

GRUB2 坏了怎么办?别慌,我遇到过不下十次这种情况。最常见的场景是:装了 Windows 后 Linux 进不去了,或者硬盘分区表被改了。修复方法分两种:

方法一:使用 Live CD 修复(推荐)

  1. 用 Ubuntu Live USB 启动,选择「试用 Ubuntu」
  2. 打开终端,挂载根分区:sudo mount /dev/sda2 /mnt
  3. 挂载 EFI 分区(如果是 UEFI 模式):sudo mount /dev/sda1 /mnt/boot/efi
  4. 绑定必要的目录:
sudo mount --bind /dev /mnt/dev
sudo mount --bind /proc /mnt/proc
sudo mount --bind /sys /mnt/sys
  1. chroot 进入系统:sudo chroot /mnt
  2. 重新安装 GRUB:
# BIOS 模式
grub-install /dev/sda

# UEFI 模式
grub-install --target=x86_64-efi --efi-directory=/boot/efi --bootloader-id=Ubuntu
  1. 更新配置:update-grub
  2. 退出 chroot,重启:exit && sudo reboot

方法二:使用 Boot-Repair 工具

如果你觉得手动操作太麻烦,可以用 Boot-Repair。它是个图形化工具,一键修复:

# 在 Live CD 中运行
sudo add-apt-repository ppa:yannubuntu/boot-repair
sudo apt update
sudo apt install boot-repair
boot-repair

选择「Recommended repair」,它会自动检测并修复 GRUB。嗯,这个工具我推荐给新手用,但作为工程师,我建议你还是学会手动修复,毕竟不是所有环境都有图形界面。

避坑指南:我曾经在修复一台服务器时,忘了挂载 /boot 分区(它是独立分区),结果 grub-install 虽然成功了,但内核文件根本没装对位置。重启后直接黑屏。记住:如果 /boot 是独立分区,一定要先挂载它。

最后说一句,GRUB2 的配置文件虽然看起来复杂,但核心逻辑就三条:别直接改 grub.cfg、用 update-grub 生成、UUID 比设备名靠谱。掌握了这三点,多系统启动的 80% 问题你都能自己搞定。