装完Windows和Ubuntu双系统后,很多朋友都会遇到一个头疼的问题——重启电脑直接进了Windows,Ubuntu就像人间蒸发了一样。这种情况我遇到过不下十次,每次帮人处理都能看到对方一脸懵的表情。其实根本原因很简单:Windows安装程序会霸道地覆盖掉MBR或EFI分区中的GRUB引导记录。
这里有个冷知识:Windows和Linux的引导机制完全不同。Windows使用bootmgr或winload.efi,而Linux依赖GRUB这个"万能引导器"。当你后安装Windows时,它会默认认为自己是唯一的操作系统,直接把引导权抢走。有趣的是,如果你先装Windows再装Ubuntu,GRUB通常会聪明地把Windows启动项包含进来,但反过来Windows可不会这么"友好"。
我遇到过最极端的情况是,某些品牌机的BIOS还会偷偷搞小动作。比如某款戴尔笔记本会在检测到Windows系统时,自动把Ubuntu的EFI启动项隐藏起来。这时候不仅需要修复GRUB,还得进BIOS手动把Ubuntu的启动项调出来。
当发现Ubuntu启动项丢失时,别急着重装系统。准备一个Ubuntu安装U盘(和你系统版本一致),插入电脑后重启。在BIOS启动菜单中选择U盘启动,但注意不要选"Install Ubuntu",而是选择"Try Ubuntu"进入试用模式。
进入Live CD环境后,打开终端。这时候我们需要先搞清楚磁盘分区情况。我强烈建议先用这个命令查看:
bash复制sudo fdisk -l
输出结果可能会让你眼花缭乱,重点找两类分区:一个是EFI系统分区(通常300MB左右,文件系统是FAT32),另一个是Linux的/boot分区(如果有单独划分的话)。在我的联想Yoga上,EFI分区是/dev/nvme0n1p1,而/boot是/dev/nvme0n1p6。
这里有个实用技巧:如果记不住分区编号,可以用lsblk -f命令,这个输出更直观,能直接看到文件系统类型和挂载点。我曾经帮人修复时,发现他把/boot单独分在了SD卡上,结果SD卡接触不良导致启动失败,这种奇葩情况用lsblk一眼就能看出来。
知道分区编号后,我们需要临时挂载它们。先创建一个临时目录:
bash复制sudo mkdir /media/tempdir
然后挂载你的EFI或/boot分区。这里有个容易踩坑的地方:如果你的/boot是单独分区,应该挂载它;如果没有单独/boot分区,就要挂载根分区。我建议两个都挂载检查下:
bash复制sudo mount /dev/nvme0n1p6 /media/tempdir # 假设这是/boot分区
sudo mount /dev/nvme0n1p1 /media/tempdir/efi # 挂载EFI分区
挂载后一定要检查内容。正确的/boot分区应该包含vmlinuz和initrd.img这些内核文件,而EFI分区会有/EFI/ubuntu这样的目录。有次我遇到个案例,用户误把Windows的恢复分区当成EFI分区,结果折腾半天发现挂载错了。
确认分区无误后,就可以重装GRUB了。这里分两种情况:
对于传统BIOS+MBR的系统:
bash复制sudo grub-install --boot-directory=/media/tempdir/boot /dev/nvme0n1
对于UEFI系统:
bash复制sudo grub-install --efi-directory=/media/tempdir --bootloader-id=ubuntu
这个步骤最容易出问题。我见过最常见的错误是忘记加--bootloader-id参数,导致GRUB安装到了默认位置,和Windows的引导冲突。还有个隐藏陷阱:某些主板对EFI分区的大小很挑剔,如果分区小于100MB可能会失败。
安装完成后别急着重启,先更新下GRUB配置:
bash复制sudo update-grub2
这个命令会扫描所有磁盘上的操作系统,重新生成引导菜单。看到它识别出Windows和Ubuntu就说明成功了。我在华为MateBook上遇到过特殊情况,需要额外安装os-prober包才能正确检测Windows。
如果上述方法都不奏效,或者你连Live CD都没有,别慌!GRUB本身就有强大的救援功能。重启电脑时按住Shift键(UEFI系统可能是Esc键)可以强制进入GRUB菜单。如果连菜单都不显示,可以尝试连续按这些键。
进入GRUB命令行后(显示grub>提示符),首先要找到你的Linux分区。输入:
code复制ls
这会列出所有存储设备,比如(hd0,gpt1)这样的标识。接下来就是耐心地一个个检查:
code复制ls (hd0,gpt1)/
如果看到"unknown filesystem"就跳过,直到找到显示正常目录结构的分区。重点找包含/boot的分区。我开发了一套快速定位技巧:先找大的分区(因为/通常很大),然后检查是否有/etc目录(因为/etc/fstab包含挂载信息)。
找到正确分区后,设置root并加载内核:
code复制set root=(hd0,gpt8)
linux /boot/vmlinuz-5.15.0-76-generic root=/dev/nvme0n1p8
initrd /boot/initrd.img-5.15.0-76-generic
boot
这里有个救命技巧:输入linux /boot/vmlinuz-后按Tab键可以自动补全内核版本。如果补全失败,说明找错分区了。有次我帮人远程调试,发现他因为/boot是单独分区,内核文件实际在根分区的/boot目录下,路径要写成/vmlinuz-xxx才行。
成功进入系统后,第一件事就是巩固战果。除了之前提到的update-grub2,我强烈建议做这几件事:
bash复制sudo cp /boot/grub/grub.cfg /boot/grub/grub.cfg.bak
bash复制GRUB_TIMEOUT=10 # 建议保持10秒以上,方便调试
bash复制GRUB_CMDLINE_LINUX="acpi_osi=linux"
我有个血泪教训:曾经给小米笔记本Pro修复启动项后,没设置这个参数,结果用户更新内核后直接黑屏,又得重新来一遍救援流程。
为了避免将来再出现这类问题,我有几个实用建议:
安装系统时,建议先Windows后Ubuntu,让GRUB自动接管引导。
使用efibootmgr管理UEFI启动项:
bash复制sudo efibootmgr -v # 查看当前启动项
sudo efibootmgr -o 0000,0001 # 设置启动顺序
bash复制sudo dd if=/dev/nvme0n1p1 of=~/efi_backup.img bs=4M
有次我帮一个科研团队恢复服务器,发现他们每周自动备份EFI分区,结果节省了数小时故障排查时间。这个好习惯值得学习。
最后分享几个特殊案例的处理经验:
案例1:某用户反馈修复后启动时出现"error: symbol 'grub_calloc' not found"。这是因为GRUB模块版本不匹配,需要进入Live CD后彻底清除旧GRUB再重装:
bash复制sudo apt purge grub-efi-amd64
sudo apt install --reinstall grub-efi-amd64
案例2:Surface Pro设备修复后触控屏失效。这类二合一设备往往需要特殊内核参数:
bash复制GRUB_CMDLINE_LINUX="i915.enable_psr=0"
案例3:双硬盘用户(SSD+HDD)安装系统后,拔掉HDD导致无法启动。这是因为GRUB默认安装到了第二块硬盘。这种情况需要在安装时指定目标磁盘:
bash复制sudo grub-install --target=x86_64-efi --efi-directory=/boot/efi --bootloader-id=ubuntu --recheck /dev/nvme0n1
记住,每个电脑的硬件配置都可能有特殊之处。遇到奇怪问题时,多查查该型号设备的已知问题。我维护了一个各品牌笔记本的GRUB问题清单,修复效率能提高不少。