免费获取学习方案
ARTICLE DETAIL

资讯详情

深耕编程基础知识与建站技术分享的一线实战洞察。

别再乱改grub.cfg!GRUB2配置、UEFI/BIOS双模式与故障排查指南

别再乱改grub.cfg!GRUB2配置、UEFI/BIOS双模式与故障排查指南 如果你也折腾过多系统启动那你八成听过这样一句劝“grub.cfg别乱改”。但反过来很多人恰恰是因为不知道改哪里才去硬改grub.cfg的。这篇东西就写给所有被启动菜单折磨过的人我会从GRUB2的工作机制讲起带你走一遍“改配置、生成菜单、安装引导、双模式兼容”的完整流程并且把UEFI和BIOS两种固件模式分开说清楚。读完你不仅能稳住自己的多系统环境还能帮朋友救急修启动菜单。这个内容适合谁双系统玩家、偶尔折腾Live USB的爱好者、搞Linux运维想补一补引导细节的新人以及手头有老电脑又想玩新系统的人。我不会让你背命令但会告诉你在哪里执行命令、为什么是这条命令、出错时最该查什么。1. 先搞清楚为什么不能直接改grub.cfg1.1 grub.cfg的真面目它是生成物不是配置文件很多人第一次接触GRUB打开/boot/grub/grub.cfg一看全是脚本片段、菜单入口、变量赋值密密麻麻于是下意识把它当成配置文件来改。这是最大的误解。GRUB2和当年GRUB Legacy最大的区别就在这里grub.cfg本质上是根据一组模板和系统状态自动生成的产物它的内容由/etc/default/grub里的变量、/etc/grub.d/里的脚本、以及grub-mkconfig扫描到的内核和系统信息共同决定。打个比方grub.cfg相当于烤好的一块面包/etc/default/grub是面粉和水/etc/grub.d/是烘焙模具。你直接去捏面包下次重新烤的时候一切白费只有改面粉配方和模具烤出来的面包才会稳定地变成你想要的样子。所以正确的做法永远是编辑etc/default/grub和etc/grub.d/下的脚本然后执行update-grub或grub-mkconfig -o /boot/grub/grub.cfg重新生成。只要你直接手改grub.cfg系统更新内核、你重装某个系统、甚至运行一次os-prober都可能把改动冲掉到时候菜单乱了还不知道哪一步出的问题。1.2 直接改配置的三种典型翻车现场我自己就见过、也帮人修过不少直接改grub.cfg造成的故障归纳起来主要有三种典型表现。第一种是“写入语法错误导致启动卡在GRUB命令行”。grub.cfg的语法虽然不算复杂但括号、引号、菜单层级错一个字符整个菜单就废了。一旦它不能被解析GRUB会在启动时直接掉进grub命令提示符。对新手来说这种界面很吓人实际上处理方式也不友好。第二种是“内核参数写错导致开机黑屏或循环重启”。比如有人为了调显卡驱动往linux行加参数结果参数名拼错内核直接panic连系统都进不去只能靠Live USB去改回来。第三种是“菜单入口顺序错乱甚至整个菜单消失”。因为grub-mkconfig会根据内核文件名自动生成入口你手动加了一个“旧内核启动项”之后下次更新内核旧内核文件被清理菜单里就会残留一个根本启动不了的死入口。这还只是直接改grub.cfg的直观风险如果你改的是内容没错但没考虑到UEFI安全引导的签名校验那麻烦更大——后面我会专门讲UEFI模式下的特殊处理。1.3 正确的配置工作流是什么格式化一点说GRUB2的配置工作流应该是这样# 第一步修改主配置文件设置默认启动项、超时时间、内核参数等 sudo vim /etc/default/grub # 第二步按需修改 /etc/grub.d/ 下的脚本比如调整菜单顺序、添加自定义入口 # 一般不需要动 10_linux 和 30_os-prober新增内容建议放在 40_custom # 第三步重新生成 grub.cfg sudo update-grub # 或者手动执行 sudo grub-mkconfig -o /boot/grub/grub.cfg不同发行版命令略有差异Debian/Ubuntu系有update-grub这个便捷包装Arch系一般直接用grub-mkconfig。不管哪种最终目的都是让生成器重新读取配置、扫描内核和系统输出一份新鲜的grub.cfg。养成这个习惯之后你再也不会被菜单问题搞得头皮发麻。2. 动手配置前先摸清固件模式和分区状态2.1 确认当前是UEFI还是BIOS启动决定一切后续操作多系统启动配置里“UEFI还是BIOS”不是选择题而是决定你所有后续操作的起点。因为GRUB在两种模式下的安装目标、文件路径、启动方式都完全不同。你可以在运行中的Linux里快速检查# 方法一查看 /sys/firmware/efi 是否存在 [ -d /sys/firmware/efi ] echo UEFI模式 || echo BIOS/传统模式 # 方法二使用 efibootmgr如果该命令存在且能运行说明是UEFI efibootmgr # 方法三查看启动日志 journalctl -b | grep -i efi\|bios | head -20看到efibootmgr输出了BootOrder、Boot0000之类的条目基本就是UEFI模式。如果提示Fatal: Could not read from the boot manager通常就是BIOS模式。这个确认不能跳过因为同样一台电脑你去grub-installBIOS模式下要往MBR或分区引导扇区写引导代码UEFI模式下则要把引导文件放到EFI系统分区ESP并处理NVRAM启动项。方向错了轻则安装后引导不了重则把你原本正常的系统入口也搅乱。2.2 分区方案速查/boot分区与EFI分区各管什么事搞清楚固件模式后你还得知道自己机器里的分区大概是个什么结构。这里快速区分两个容易混淆的概念。BIOS模式下Linux通常需要一个/boot分区也可以不单独分但为了稳妥很多发行版还是建议分一个GRUB的core.img放在这个分区的/boot/grub下引导代码写在磁盘MBR或分区引导扇区里。UEFI模式下重点看EFI系统分区也就是ESP。ESP是一个FAT32格式的小分区一般几百MB挂载在/boot/efi或/efi下。GRUB的EFI可执行文件比如grubx64.efi就放在ESP上的/EFI/目录树里。固件通过NVRAM里的启动项找到这个文件然后把它加载起来。你可以用下面的命令快速查看# 显示块设备概况找到ESP或/boot分区 lsblk -f # UEFI模式下查看ESP挂载情况 findmnt /boot/efi # BIOS模式下查看/boot挂载情况 findmnt /boot搞清楚这些你在动手改配置的时候才不会改错地方也不会在执行安装命令时把参数写岔。2.3 备份与恢复环境准备如果说前面是“摸清家底”这一步就是“买保险”。配置GRUB的过程中最让人慌乱的场景就是你改了半天的配置重启之后进不去系统而手头又没有工具。所以我强烈建议在动任何配置之前先花几分钟准备一个Live USB再做一次配置备份。备份主题其实很简单一个是把当前能用的grub.cfg以及相关配置备份一份另一个是记录当前磁盘分区结构。# 备份当前有效的grub.cfg保守起见连default/grub也一起备份 sudo cp /boot/grub/grub.cfg ~/grub.cfg.bak.$(date %F) sudo cp /etc/default/grub ~/grub.default.bak.$(date %F) # 保存分区布局和ESP信息 sudo parted -l ~/parted-info.txt sudo lsblk -f ~/lsblk-info.txt更重要的是准备一个系统原版的Live USB。不同发行版有各自的制作工具Ubuntu用Startup Disk CreatorArch有官方镜像的dd写入方法Fedora有Fedora Media Writer。为什么强调“原版”因为你不能等出事的时候再去找工具而且原版Live环境里的GRUB工具链是最匹配的救援时不容易出幺蛾子。3. 核心实操通过 /etc/default/grub 与 /etc/grub.d/ 定制启动菜单3.1 最常用的 /etc/default/grub 参数详解现在进入正题。/etc/default/grub是整个GRUB2配置的中心枢纽绝大多数自定义需求只要改这个文件就够了。下面我按实用程度排个序把关键参数讲清楚。# 默认启动项可以用菜单序号也可以用菜单名称 GRUB_DEFAULT0 # 等待用户选择菜单的时间单位秒设成0表示直接启动默认项 GRUB_TIMEOUT5 # 默认启动项的“替补”如果默认项异常可以用第二个候补 GRUB_DEFAULT12 # 传给内核的命令行参数 GRUB_CMDLINE_LINUX_DEFAULTquiet splashGRUB_DEFAULT这个参数值得细说。用数字的时候序号从0开始也就是第一个菜单项是0第二个是1。用引号指定名称也行比如GRUB_DEFAULTAdvanced options for Ubuntu但名称会随系统更新变化数字也不一定稳定因为菜单项顺序可能因内核更新而改变。更稳妥的方式是GRUB_DEFAULTsaved配合GRUB_SAVEDEFAULTtrue这样每次启动后GRUB会记住你最后选中的项下次默认启动它。如果你经常切换Windows和Linux这个配置能省不少事。GRUB_TIMEOUT设置的是菜单等待时间。如果在UEFI模式下你可能会遇到“GRUB_CMDLINE_LINUX_DEFAULT里的quiet splash没生效”的情况这个多半是因为你没有定位到正确的菜单项或者忘了重新生成配置。另外如果你把GRUB_TIMEOUT设成0有些主板在个别情况下会直接跳过GRUB菜单让你连进Menu的余地都没有这时候按Shift键或Esc键又不一定有用所以我建议日常至少给个3~5秒。3.2 一个快速可用的配置示例为了让你有个直观参考我放一份我常用的示例配置你可以按照自己实际需求改# 文件位置/etc/default/grub GRUB_DEFAULTsaved GRUB_SAVEDEFAULTtrue GRUB_TIMEOUT5 GRUB_DISTRIBUTORlsb_release -i -s 2/dev/null || echo Debian GRUB_CMDLINE_LINUX_DEFAULTquiet splash # 如果内核崩溃可以临时加上 nomodeset 或 acpioff 等参数排查 GRUB_CMDLINE_LINUX # 默认不启用os-prober多系统时把它打开 GRUB_DISABLE_OS_PROBERfalse这段配置的意思是默认启动上一次选择的系统菜单显示5秒正常启动时显示启动logo和quiet splash输出同时打开os-prober检测其他操作系统。GRUB_DISABLE_OS_PROBERfalse在多系统场景里非常重要因为现在有些发行版为安全考虑默认关掉了os-prober不打开它你的Windows或者另一个Linux就压根不会出现在菜单里。3.3 自定义菜单标题、超时与内核启动参数刚才那一步属于基础配置接下来看几个高频定制需求。需要修改菜单标题时很多人第一反应是去改grub.cfg里的menuentry xxx。千万别这么做而是要改/etc/grub.d/10_linux脚本里的变量或者用/etc/default/grub里的GRUB_DISTRIBUTOR去影响标题前缀。更简单的方式是直接修改内核的title在/etc/grub.d/10_linux里有类似title_correction之类的逻辑。但对大多数用户来说最省心的方式是在40_custom里新增自己命名的菜单项然后通过GRUB_DEFAULT指向它。需要调整内核启动参数时像quiet代表隐藏内核输出splash代表显示开机画面nomodeset代表禁用KMS显卡模式切换acpioff可以用来排查电源管理相关启动问题。这些参数最终会拼进linux那一行# 查看当前生效的启动项确认参数是否生效 grub-editenv list cat /proc/cmdline如果你在/proc/cmdline里没看到quiet或splash说明新参数没进去十有八九是没重新生成grub.cfg或者你改错了发行版对应的配置文件比如有的发行版用/etc/default/grub有的还要看/etc/default/grub.d/下的覆盖文件。3.4 使用 /etc/grub.d/ 下的自定义脚本添加特殊入口/etc/grub.d/目录里有一堆带数字前缀的脚本数字决定了它们在grub.cfg里出现的顺序。一般规则是00_header生成头部10_linux扫描本机Linux内核20_linux_xen管Xen虚拟化30_os-prober检测其他系统40_custom留给用户自己写。要添加自定义菜单项最正规的姿势是在40_custom里追加内容。举个例子如果你想手写一个启动另一个分区系统的入口比如一个特殊的发行版os-prober检测不到可以这样#!/bin/sh exec tail -n 3 $0 menuentry My Custom Linux { set root(hd0,gpt2) linux /vmlinuz-linux root/dev/sda3 ro quiet initrd /initramfs-linux.img }exec tail -n 3 $0这行是固定头别删。set root(hd0,gpt2)表示指定分区这里的命名方式和/dev/sdaX不同hd0是第一块磁盘gpt2是GPT分区表的第二个分区。如果你需要用UUID来指定可以用search --no-floppy --fs-uuid --setroot 你的分区UUID这样更稳妥不会因为盘符漂移而挂掉。这里必须强调40_custom只负责定义菜单入口它不会自动扫描系统。如果你要检测和生成Linux或Windows入口靠的还是10_linux和30_os-prober。所以自定义脚本适合你做“额外的手工入口”而常规系统的入口尽量让生成器自动管理。3.5 重新生成grub.cfg的命令差异说明改完配置最后一步就是把配置变成实实在在的grub.cfg。这里有两个常用命令很多人分不清。update-grub是Debian/Ubuntu系的便捷脚本它本质上就是执行grub-mkconfig -o /boot/grub/grub.cfg。在Arch、Fedora这些发行版上不一定有update-grub但你通常可以直接用grub-mkconfig -o。# Debian/Ubuntu sudo update-grub # Arch / Fedora / 其他 sudo grub-mkconfig -o /boot/grub/grub.cfg注意如果你用的是UEFI模式grub.cfg的位置依然是/boot/grub/grub.cfg不过/boot可能是单独的挂载点也可能就是根分区下的一个目录只要生成路径和你实际启动加载路径一致就行。生成的时候屏幕上会列出检测到的系统比如“Found linux image: /boot/vmlinuz-...”以及“Found Windows Boot Manager on /dev/nvme0n1p1”之类。如果这里没出现预期系统问题基本出在os-prober上我们后面会专门聊。4. UEFI与BIOS双模式下的配置差异与安装细节4.1 两种固件模式下的GRUB安装路径与NVRAM引导条目前面说了固件模式决定安装目标。这里我把差异集中对比一下方便你一眼看明白。对比维度BIOS/传统模式UEFI模式引导代码位置MBR或分区引导扇区ESP内EFI/目录下的.efi文件配置文件位置/boot/grub/grub.cfg/boot/grub/grub.cfg/boot可能是ESP也可是独立分区安装命令grub-install /dev/sdX磁盘设备grub-install --targetx86_64-efi --efi-directory/boot/efi启动项管理由MBR代码决定固件NVRAM里的BootOrderefibootmgr可查支持安全启动一般不涉及需要shim签名如shimx64.efiUEFI模式还有一个特殊概念NVRAM引导条目。你在安装GRUB时grub-install会自动创建一条UEFI启动项这条启动项指向ESP里的grubx64.efi。如果这条启动项被清掉比如清CMOS、Windows重装、某些主板更新即使ESP文件还在固件也不知道去启动它。这时候你可以用efibootmgr手动创建或修复# 查看当前UEFI引导项 efibootmgr -v # 手动创建一条指向Linux引导器的UEFI启动项 sudo efibootmgr -c -d /dev/nvme0n1 -p 1 -L Linux Boot Manager -l \\EFI\\ubuntu\\shimx64.efi-d是磁盘设备-p是EFI分区所在的分区号-l是引导文件路径反斜杠是UEFI路径的标准写法。这里用shimx64.efi是为了兼容安全启动如果你关闭了安全启动也可以指定grubx64.efi。而在BIOS模式下没有NVRAM引导项这个概念。grub-install直接往磁盘的MBR或分区引导扇区写引导代码BIOS根据“第一启动设备”的设置读MBR然后交给GRUB。所以BIOS模式下装好GRUB后你只需要确认BIOS启动顺序是这块盘优先即可。4.2 UEFI模式下grub-install与efibootmgr的用法如果你很明确自己要在UEFI模式装GRUB一般流程是这样# 1. 确认ESP已挂载到 /boot/efi sudo mount /dev/nvme0n1p1 /boot/efi # 2. 安装GRUB UEFI版本target指定为x86_64-efi sudo grub-install --targetx86_64-efi --efi-directory/boot/efi --bootloader-idLINUX --recheck # 3. 重新生成grub.cfg sudo grub-mkconfig -o /boot/grub/grub.cfg参数里--efi-directory必须是ESP挂载点--bootloader-id是显示在固件启动菜单里的名字--recheck会重新探测设备映射。有些主板对“Windows Boot Manager”这个名字有特殊偏好如果你希望GRUB出现在BIOS启动菜单原生的Windows项之外可以换一个ID比如--bootloader-idubuntu或--bootloader-idgrub。装完后用efibootmgr -v确认启动项。如果系统在UEFI下但从这个启动项启动时报错比如“Selected boot device failed”可以检查ESP上的文件路径是否和NVRAM里的路径完全一致。注意UEFI路径用反斜杠courtesy 的EFI\\LINUX\\grubx64.efi和实际文件位置要对应。4.3 BIOS模式下grub-install与MBR的配合BIOS模式下安装GRUB命令更简单但坑也不少# 安装GRUB到磁盘的MBR。注意这里传的是整块磁盘不是分区 sudo grub-install /dev/sda # 重新生成配置 sudo grub-mkconfig -o /boot/grub/grub.cfgBIOS模式下grub-install会把引导代码写到/dev/sda开头的MBR区域同时把core.img等文件安装到/boot/grub。有一个常见误区是有人写成sudo grub-install /dev/sda1这会写到分区引导扇区而不是MBR。除非你非常明确要写到分区引导扇区比如配合其他引导管理器实现链式加载否则日常直接写整盘就对了。另一个BIOS模式的坑是如果磁盘是GPT分区表你可能需要在磁盘开头留一个1MB左右的“BIOS boot”分区GRUB才能把引导代码放进去。如果没留grub-install可能会报“embedding is not possible”错误。以我经验碰到这种报错不要硬试先把分区表留好这个分区再装。4.4 多系统场景Windows与Linux双系统菜单配置说到多系统最典型的就是Linux和Windows共存。GRUB默认不会主动去读Windows分区而是通过os-prober去探测。在Debian/Ubuntu上你需要先确保/etc/default/grub里有GRUB_DISABLE_OS_PROBERfalse然后重新生成配置。如果生成过程中看到了类似Found Windows Boot Manager on /dev/nvme0n1p1的输出说明Windows入口已经加进菜单。Windows入口的启动方式通常是链式加载也就是GRUB定位到Windows Boot Manager所在分区然后用chainloader把控制权交给它menuentry Windows Boot Manager { search --fs-uuid --setroot $UUID chainloader /EFI/Microsoft/Boot/bootmgfw.efi }在UEFI模式下Windows以bootmgfw.efi作为入口GRUB把它当普通EFI程序加载。在BIOS模式下则不同Windows得通过NTLDR或微软引导器链式加载写法会有差异。所以很多人说“GRUB里Windows坏了”大部分原因是模式不匹配你在UEFI的GRUB里企图链式加载BIOS模式安装的Windows或在BIOS GRUB里加载UEFI的Windows都很难办。如果os-prober找不到Windows优先怀疑三件事os-prober没安装、ESP没有挂载、Windows休眠没完全关机Windows的快速启动会让分区处于不干净状态。最后一个尤其坑你需要在Windows里关掉“快速启动”或者执行一次真实的“重启”而不是“关机再开机”。5. 常见问题与排查技巧实录5.1 系统更新后菜单丢失我遇到最多的求助案例就是“我更新了内核/重装了Windows之后GRUB菜单里原来的Linux没了”或“菜单直接变成grub界面”。内核更新后菜单丢失通常是重生成配置时没有正确扫描到新内核可以用Live USB启动后 chroot 进入系统重新生成引导。具体做法是启动Live环境挂载根分区和必要目录然后chroot再执行update-grub。但chroot之前建议先把/proc、/sys、/dev、/boot如果是独立分区都挂好否则生成脚本可能探测不到内外设结果生成出一个残缺的grub.cfg。# 以挂载根分区到/mnt为例再假设/boot是独立分区 sudo mount /dev/sda2 /mnt sudo mount /dev/sda1 /mnt/boot # 如果/boot独立 sudo mount --bind /dev /mnt/dev sudo mount --bind /proc /mnt/proc sudo mount --bind /sys /mnt/sys sudo chroot /mnt /bin/bash # 在chroot环境里 mount -t efivarfs efivarfs /sys/firmware/efi/efivars # UEFI模式需要 update-grub exit # 随后卸载所有挂载这套流程相当于在Live环境里进入旧系统“原地修车”比直接修改落盘grub.cfg可靠得多。在chroot里执行完update-grub后退出并重启即可。5.2 os-prober找不到Windows该怎么办os-prober找不到Windows是双系统用户的老大难。前面提过几个原因这里展开说说排查方法。先用命令手动探测一下sudo os-prober如果它什么都没输出那好问题定位到“os-prober根本没看到Windows”。接下来查分区lsblk -f看看Windows的EFI分区是否被挂载。os-prober在某些情况下需要访问ESP和Windows系统分区的文件来识别Boot Manager如果ESP没有被挂载到/boot/efi它可能直接跳过。所以先挂载ESP再跑一次sudo mount /dev/nvme0n1p1 /boot/efi sudo os-prober还有一种情况是Windows的快速启动导致NTFS分区被标记为“脏”状态os-prober不愿意探测。不用进Windows你可以用ntfsfix尝试清理NTFS脏标记但不保证成功更安全的做法还是去Windows里关闭快速启动然后执行“重启”不是关机来彻底释放分区。5.3 UEFI引导项消失或启动顺序被打乱这种情况一般发生在你重装Windows、重置NVRAM、或者清空CMOS之后。表面上你的Linux分区文件都还在ESP里的grubx64.efi也还在但固件不知道怎么去启动它。我们用efibootmgr搞定的方法上面已经给了这里再补充一个“用BootOrder调整到第一位”。# 查看当前启动项 efibootmgr # 假设Linux的Boot条目是Boot0003将它设为第一启动项 sudo efibootmgr -o 0003,0001,0002注意-o后面跟着的是启动项编号顺序就是BootOrder的顺序。调整完可以用efibootmgr -v确认。如果你发现Linux启动项根本不存在就用efibootmgr -c新建一条或者干脆在上一个安装步骤重新执行一次grub-install它会自动重新注册NVRAM启动项。5.4 字体和分辨率异常、菜单显示不全这个问题虽然不影响启动但很影响体验。GRUB2在UEFI模式下默认会使用固件的图形输出分辨率可能偏低或者字体发虚。想要更好的显示效果可以在/etc/default/grub里设置GRUB_GFXMODEGRUB_GFXMODE1920x1080,1280x720,auto GRUB_GFXPAYLOAD_LINUXkeepGRUB_GFXMODE指定GRUB菜单的分辨率keep表示把解析度传给内核这样启动后终端分辨率也和GRUB一致。设置了不生效多数是因为显卡驱动或固件不支持该分辨率这时候auto会帮你选一个能用的。字体文件如果在/boot/grub/fonts/下缺失也可能导致菜单出现方格或乱码重装grub-common或grub2-common包通常能恢复。5.5 快速排查动作清单最后整理一份高频排查动作清单遇到启动菜单问题按顺序做能帮你省不少时间用lsblk -f确认所有分区和文件系统类型是否正常。确认ESP是否挂载findmnt /boot/efi。手动执行sudo os-prober观察是否能检测到其他系统。重新生成配置sudo grub-mkconfig -o /boot/grub/grub.cfg观察输出有无异常。如果是UEFI用efibootmgr -v检查启动项顺序和引导文件路径。如果圈定是GRUB文件问题可以用Live USB启动后chroot再修复。这套流程我自己在救援的时候反复用过它把“查分区、查挂载、查探测、查生成、查NVRAM”串成了一条线基本可以覆盖90%以上的菜单类故障。最后的几点经验玩GRUB2这几年我最大的体会是不要怕启动菜单问题但一定要敬畏配置流程。grub.cfg确实不能乱改不是因为GRUB多脆弱而是因为真正的配置源头和维护入口明明放在更合理的地方直接改生成文件属于绕开系统自己给自己埋坑。你一旦掌握了/etc/default/grub/etc/grub.d/grub-mkconfig这个铁三角多系统启动菜单就不再是玄学而是完全可以预期、可以备份、可以恢复的标准化组件。另外真建议你在每次配置稳定之后把当时的default/grub、自定义脚本内容、分区布局和efibootmgr信息都存到一个私有仓库或者笔记里。等你下次重装或换硬盘这些记录比任何教程都管用。启动菜单这件事说到底是“配置养成习惯、恢复靠备份、疑难靠排查流程”三个词只要这三件事做到位GRUB2就再也难不倒你。
返回列表