ARTICLE · INTELLIGENCE

战地情报 · 详情页

来自尧图项目组的一线实战观察与深度解析

Ubuntu开机卡在grub>命令行?一文讲透排查与修复全攻略

Ubuntu开机卡在grub>命令行?一文讲透排查与修复全攻略

开机按下电源键,屏幕没出现Ubuntu的紫色界面,也没看到登录页,反而停在一个黑色背景的命令行窗口,提示符就三个字符:grub>。第一次遇见的朋友基本都会慌,觉得系统是不是彻底坏了,要不要直接重装。我见过不少这样的求助,其实这个现象在Ubuntu用户里不算少见,而且绝大多数情况根本不需要重装系统,甚至不用U盘进Live环境,在命令行里敲几行命令就能把系统重新拉起来。

这篇文章就把整条链路讲清楚:怎么区分你卡在了GRUB的哪个阶段,怎么在grub>提示符下手动引导系统,进入系统后怎么找到根因做永久修复,以及万一系统进不去时怎么用Live USB配合chroot做离线救援。无论你是Windows和Ubuntu双系统用户,还是公司服务器上跑着Ubuntu的运维新手,都可以按这个顺序排查一遍。

1. 先确认你卡在的到底是哪一层GRUB界面

1.1 三种容易混的界面,别一上来就乱敲命令

不少求助帖把“开机进入grub模式”混为一谈,但GRUB其实有三种界面,处理方式差别很大。

第一种是正常的GRUB菜单,紫色或黑底,列出Ubuntu、Advanced options for Ubuntu、以及可能的Windows Boot Manager。这是正常状态,不算问题。很多人急着把系统默认项改成直接登录,反而把GRUB菜单弄没了,那是另一种坑。

第二种是grub>命令行。GRUB核心已经加载了,但它找不到可用的grub.cfg配置文件,于是把你丢到一个最小命令行里。这个环境下部分模块还没加载,但ls、set、insmod这些内置命令还能用,所以有较大操作空间。

第三种是grub rescue>救援模式。这是更早期的阶段,GRUB连自己的一些核心模块都没找到,通常提示error: unknown filesystem或者no such partition,命令也很少,基本靠set和ls救场。

判断方法很简单:看提示符。grub>和grub rescue>的修复路径完全不同,后面会分别说明。不要看到命令行就随便敲reboot或者乱按方向键,先确认状态。

1.2 为什么Ubuntu启动会经过GRUB这一关

要从根上理解这个问题,得先知道电脑启动的基本顺序。传统BIOS或UEFI固件启动后,会按优先级寻找可启动设备,找到引导加载器。Ubuntu默认用的引导加载器就是GRUB 2,它负责把你选择的系统内核加载进内存,再把控制权交给内核。

GRUB 2的工作流程大致分两步:第一步是加载自身核心,第二步是从/boot/grub目录读取配置、加载文件系统模块、显示菜单。只要第二步里任何一环出问题,比如配置文件损坏、分区找不到、模块路径不对,GRUB就会退到命令行。

打个比方:GRUB像一个前台接待,菜单就是前台桌上的电话本。接待本身已经站在门口了,但电话本丢了,他没法告诉你各个办公室在几楼,只好让你直接问他。grub>就是那个“你问我答但没电话本”的状态。

1.3 两行命令快速判断当前状态

进到grub>后,先别急着乱敲。第一时间输入:

ls

这条命令会列出GRUB能识别的磁盘和分区,形如(hd0)、(hd0,gpt1)、(hd0,msdos2)等。再看当前环境:

set

这会输出root和prefix的值,比如root=(hd0,gpt2)、prefix=(hd0,gpt2)/boot/grub。如果prefix指向的路径里确实存在grub.cfg,但菜单还是没出来,可以试试输入normal重新加载正常模块。如果提示file not found,那就说明prefix设置不正确,或者分区不对,后面手动引导部分会专门讲怎么处理。

2. 临时救急:从grub>命令行把系统重新拉起来

2.1 第一招:重新加载normal模块回到菜单

在grub>提示符下,最快的恢复方式往往是:

normal

如果GRUB的模块和配置其实都还在,只是加载流程中断了,这条命令会尝试重新加载正常模式,直接回到熟悉的菜单界面。我有一次就是升级完内核后菜单莫名其妙消失了,敲了normal就回来了,全程不到十秒。

如果normal提示file not found,说明GRUB找不到/boot/grub下的模块文件。这时候换第二招:用exit命令退出GRUB,可能会回到固件的启动菜单,或者直接重启,方便你进入BIOS检查启动顺序。在UEFI机器上exit通常能退到固件设置界面,传统BIOS机器则可能直接重启。

这两个命令都不破坏任何数据,可以放心试。我要提醒的是,很多人到了grub>会习惯性输入reboot,这个命令在GRUB里不一定存在,反而容易把自己绕晕。

2.2 手动引导内核:完整命令与每个参数的作用

如果normal没用,那就手动把内核加载起来。整个过程就是把GRUB应该做的引导工作自己做一遍,看似命令多,其实每一步都有明确含义。

先用ls确认分区情况,比如输出:

(hd0) (hd0,gpt1) (hd0,gpt2) (hd0,gpt3)

接着逐个检查哪个分区里有/boot/grub目录。在grub>下可以直接列出目录内容看看:

ls (hd0,gpt2)/boot/grub

如果输出了一堆.mod文件和grub.cfg,说明这就是GRUB的家。接下来把根指向这个分区:

set root=(hd0,gpt2)

然后加载Linux引导模块并指定内核参数:

insmod linux linux /boot/vmlinuz-5.15.0-xxx-generic root=/dev/sda2 ro

注意vmlinuz版本号要换成你在ls (hd0,gpt2)/boot/里看到的具体文件。如果你不确定根分区是哪个,可以先不写root=,等加载完initrd后看启动报错再调整。紧接着加载内存磁盘镜像:

initrd /boot/initrd.img-5.15.0-xxx-generic

最后启动:

boot

如果一切正常,你会看到内核输出滚动,然后进入系统登录界面。这里每一步背后都有讲究:insmod linux是告诉GRUB怎么解析Linux内核格式;linux后面指定的是内核镜像路径和传给内核的启动参数;initrd是临时的根文件系统,包含加载真正根分区所需的驱动;boot才是真正把控制系统交出去。

2.3 手动引导阶段最容易踩的三个坑

第一个坑是分区号理解错误。(hd0,gpt2)里的hd0是GRUB自己的设备编号,不是Linux里的/dev/sda。在多硬盘机器上,hd0不一定是对应/dev/sda,所以不要凭Linux里的盘序猜GRUB编号,老老实实用ls逐个探测。

第二个坑是内核和initrd不匹配。如果你ls /boot/里看到好几个vmlinuz和initrd.img,一定要选同一版本号的一组。我见过有人图省事,linux行用的新版内核,initrd行用的旧版镜像,结果启动到一半直接kernel panic。

第三个坑是根分区参数错误。如果root=给错了,内核会在挂载根文件系统时失败,报出类似Unable to mount root fs的错。这时候不要慌,回到grub>重新指定正确的根分区就行。在不确定根分区时,可以在系统休眠状态下用ls查看各分区的内容特征,比如ls (hd0,gpt3)/出现bin、etc、home等目录,就说明它是根分区。

3. 能进系统之后,按这个顺序找根因

3.1 第一时间重建GRUB菜单:update-grub

手动引导进系统只是临时救急,如果你什么都不改,下次重启大概率还会被丢进grub>。第一次登录系统后,第一件事是打开终端,执行:

sudo update-grub

这条命令会扫描当前系统已安装的内核、其他操作系统的引导信息,然后重新生成/boot/grub/grub.cfg。它本质上是grub-mkconfig -o /boot/grub/grub.cfg的封装,把缺失的“电话本”重新写出来。

绝大多数场景下,grub.cfg文件损坏、内容为空、或者上次内核安装中断导致配置没更新,一条update-grub就能解决。执行完以后建议再用cat /boot/grub/grub.cfg | grep menuentry看一眼,确认菜单项都正常生成。

3.2 /boot空间不足与旧内核残留:隐蔽的定时炸弹

如果你用的Ubuntu把/boot单独划成了一个小分区,比如300MB甚至更小,那就要格外小心。每次内核升级后,系统会尝试在/boot里写入新的vmlinuz和initrd.img文件,同时调用update-initramfs更新镜像。如果空间不足,内核安装会在半途失败,但GRUB可能已经更新了配置,指向一个不存在的镜像,于是开机直接进grub>。

排查方法很直接:

df -h /boot

如果Use%超过90%,基本就是这个问题。再看一下:

ls /boot/

如果里面堆了七八个旧内核文件,就说明清理没跟上。处理办法是让apt自动清理旧内核:

sudo apt autoremove --purge

这条命令会删除已不再需要的旧内核镜像,但要注意它不会删掉你当前正在使用的内核。我不建议手动rm /boot/vmlinuz-*,因为你可能误删正在用的内核,而且手动删除后dpkg的数据库里还有记录,下次升级时反而会出乱子。

3.3 双系统升级导致Windows“抢”了引导权

Windows和Ubuntu双系统用户遇到的grub>,原因往往不在Ubuntu自己身上,而是Windows更新“动了手脚”。Windows大版本更新后,有时会重写UEFI的NVRAM启动变量,或者把EFI系统分区里的Windows引导文件设为第一优先,结果开机要么直接进Windows,要么GRUB找不到自己的配置被丢到命令行。

这种情况的修复思路不是去Windows里折腾,而是从Ubuntu里重装GRUB并把引导顺序改回来。在能进Ubuntu的情况下:

sudo update-grub sudo grub-install

grub-install会把GRUB重新安装到磁盘的引导区域,重写启动项。然后重启,按主板快捷键进启动菜单,把ubuntu(或者带厂商名称的ubuntu条目)设为第一启动项。

另外提醒一句:Windows的“快速启动”功能在UEFI机器上有时会干扰引导流程,如果你发现Windows和Ubuntu相互切换总是出问题,可以在Windows的电源选项里临时关闭“快速启动”试试。

3.4 UUID变化:磁盘分区改完之后最常见的失联

GRUB配置里的root=UUID=xxxx,以及系统里的/etc/fstab,都是靠UUID识别分区的。UUID是分区的唯一标识,只要分区没被格式化、缩放、复制,它不会变。但问题往往出在你自己动过分区。

用GParted调整过分区大小、新建过分区、或者做过分区复制之后,原分区的UUID可能变了,或者分区的顺序发生了变化。这时候GRUB启动时按老UUID找根分区,找不到就直接进grub>。

排查方法是用blkid查看当前各分区的真实UUID:

blkid

再对照/etc/fstab里的UUID条目:

cat /etc/fstab

如果两者对不上,就把/etc/fstab里的UUID改成现在的值。同时别忘了重新生成GRUB配置:

sudo update-grub

因为grub.cfg里的root=UUID=也是按老配置生成的,不更新的话下次还是会进grub>。顺便说一句,写/etc/fstab时不要用/dev/sda2这种设备名,因为开机时设备名会随硬盘接入顺序变化,用UUID才是稳定可靠的。

4. BIOS与UEFI模式下永久修复的差别

4.1 传统BIOS机器:grub-install指向哪个磁盘

如果你的机器还是传统BIOS引导,也就是用MBR分区表,修复GRUB的姿势和UEFI机器完全不同。BIOS机器上,主板的固件会直接读取磁盘第一个扇区的引导代码,GRUB的第一阶段就写在那里。所以grub-install的目标不是分区,而是整块磁盘。

假设系统盘是/dev/sda,在能进系统的情况下执行:

sudo grub-install /dev/sda sudo update-grub

注意千万别写成grub-install /dev/sda1,那样会把GRUB装到分区里而不是MBR里,BIOS根本不会去读。多硬盘机器上还有个隐藏问题:BIOS启动时可能不是从/dev/sda读取引导,而是从另一块盘,比如一块旧数据盘。这时候即使你往/dev/sda装了GRUB,BIOS还是会从数据盘启动。最简单的验证办法是进BIOS看启动顺序,确保排在第一位的是你装GRUB的那块盘。

4.2 UEFI机器:EFI分区、efibootmgr和Secure Boot

UEFI机器就不一样了,它不读MBR,而是从EFI系统分区(ESP)里读取.efi引导文件。判断当前是UEFI还是BIOS模式,可以用:

ls /sys/firmware/efi

如果这个目录存在,就是UEFI启动。UEFI模式下修复GRUB的命令是:

sudo grub-install --target=x86_64-efi --efi-directory=/boot/efi --bootloader-id=ubuntu

这里--efi-directory指定EFI分区挂载的位置,通常是/boot/efi;--bootloader-id=ubuntu是生成启动项的名字。执行前先确认EFI分区确实挂载了:

mount | grep /boot/efi

如果没挂载,先挂载对应的分区。挂载EFI分区要特别注意,它通常是FAT32格式,不要用chmod乱改权限,否则Windows可能识别不了。

UEFI模式还有一个经常被忽略的点:NVRAM里的启动项。用:

efibootmgr -v

可以查看当前所有的UEFI启动项和顺序。如果列表里没有ubuntu,或者顺序不对,用下面这个调整:

sudo efibootmgr -o 0002,0001

把ubuntu对应的编号放到第一位。另外,如果你之前手动关过Secure Boot,建议先恢复开启状态测试一下。Ubuntu一般使用shim签名引导,Secure Boot正常情况下是能过的,如果开启后进不去,说明GRUB安装时用的不是签名版本,需要重新安装shim-signed。

4.3 为什么很多机器“修完重启又变回grub>”

这是我在实际维护中遇到最多的反馈:Live盘里跑boot-repair,明明显示成功了,重启之后还是停在grub>。拆开看,几乎都是这几个原因。

第一,root分区挂载位置不对。有人在Live环境里把根分区挂到了/mnt,但EFI分区挂到了/mnt/boot/efi,然后没有正确chroot,直接在Live系统里执行grub-install --efi-directory=/boot/efi,结果写的是Live系统的路径,等于没写。

第二,多硬盘UEFI机器上,GRUB被装到了另一块盘的EFI分区。lsblk看一下你的EFI分区到底在哪块盘上,再确认grub-install有没有指错。

第三,NVRAM里的启动项没有变化。grub-install写了文件,也生成了启动项,但主板固件设置里依然是“直接从硬盘启动”而不是“通过ubuntu引导项”。这种就要进BIOS手动调整启动顺序。

第四,也是最容易被忽略的:Windows更新又把NVRAM改了。你修好了GRUB,结果Windows下次大更新又覆盖,这是双系统的常态。没有一劳永逸的办法,只能养成定期检查启动项的习惯。

5. 进不去系统的线下救援:Live USB加chroot

5.1 制作启动盘并进入试用环境

如果连手动引导都搞不定,或者根本不知道根分区是怎么回事,那就走正规救援路线:做一个Ubuntu的Live USB启动盘,从U盘启动,选择“试用Ubuntu”,进入一个临时的桌面系统。

在Live环境里,你拥有完整的工具链,可以挂载原系统磁盘、进入chroot、重新安装GRUB。这个过程不会影响磁盘数据,只是借用Live系统的内核和工具来修复磁盘上的原系统。

我强烈建议每个Linux用户的抽屉里都放一个这样的Ubuntu启动盘,平时看起来没用,一旦系统进不去它就是救命稻草。不需要每天更新,一台Ubuntu LTS长期支持版本的安装镜像就够用几年。

5.2 chroot三步:挂载、切换、修引导

以下以UEFI机器、根分区是/dev/sda2、EFI分区是/dev/sda1为例。先用lsblk -f确认各分区的设备和文件系统类型。

第一步,挂载根分区和EFI分区:

sudo mount /dev/sda2 /mnt sudo mount /dev/sda1 /mnt/boot/efi

第二步,把Live环境里的系统虚拟文件系统绑到/mnt下,这样chroot后的环境才能正常管理进程和网络:

sudo mount --bind /dev /mnt/dev sudo mount --bind /proc /mnt/proc sudo mount --bind /sys /mnt/sys

第三步,切进原系统环境执行修复:

sudo chroot /mnt /bin/bash

现在你的终端已经“变成”原系统的根环境,直接执行:

update-grub grub-install --target=x86_64-efi --efi-directory=/boot/efi --bootloader-id=ubuntu

完成后退出chroot:

exit

再按顺序卸载分区:

sudo umount /mnt/sys /mnt/proc /mnt/dev sudo umount /mnt/boot/efi sudo umount /mnt

然后重启,拔掉U盘,看能否正常进系统。如果你用的是LVM逻辑卷,挂载前要先激活卷组:

sudo vgchange -ay

否则/dev/sda2对应的逻辑卷路径是不会出现的。我之前帮一位朋友恢复系统时就是漏了这一步,折腾了大半天才发现卷组没激活。

5.3 懒人方案:boot-repair的自动化修复

如果你不想手动敲命令,boot-repair是这个场景里最常用的图形化工具。在Live环境的终端里执行:

sudo add-apt-repository ppa:yannubuntu/boot-repair sudo apt update sudo apt install boot-repair

启动后点“推荐修复”,它会自动做几件事:扫描磁盘上的系统、探测已有的GRUB配置、重新安装GRUB到对应位置、重建UEFI启动项,最后生成一份修复日志。

这个工具适合哪些情况?适合你完全确定自己的根分区和EFI分区没被破坏,只是引导配置丢了或者启动项乱了。如果磁盘本身挂了、分区表损坏,boot-repair也无力回天,日志里会清楚地告诉你哪里失败。另外要注意,boot-repair在自动修复时可能会改动分区标志,修复完成后建议再确认一遍/etc/fstab里有没有设备名依赖。

5.4 应急修复工具箱做个简单对比

方法适用场景操作难度需要的外部工具
grub>命令行手动引导GRUB核心能加载,配置丢失中无
进系统后update-grub能进系统,仅配置缺失低无
系统内grub-install能进系统,引导区域损坏低无
Live USB + chroot完全无法引导入系统中高启动U盘
boot-repair自动修复不熟悉命令行,需快速处理低启动U盘和网络

我的建议是先根据能否进系统选择大方向,能进系统就在系统内修,不能进就上Live。命令行能力允许的情况下,优先用chroot手动修,因为你清楚每一步做了什么,出了问题也知道往哪个方向排查。

6. 让GRUB以后少出问题的几个现实习惯

6.1 内核升级之后不要跳过菜单重建

大部分时候,Ubuntu在更新内核后会自动调用update-initramfs和update-grub,不需要你手动操作。但如果你经常手动管理内核,或者不定期清理系统,就会打破这个自动流程。我给自己定的习惯是:每次apt upgrade完成了内核相关更新后,顺手执行一次sudo update-grub,哪怕明知道它已经被自动执行过一次。

这样做的另一个好处是,如果/boot空间不足导致内核安装中断,你能在执行update-grub时更早发现异常,而不是等重启后才发现进不了系统。防患于未然,成本只是一条命令的时间。

6.2 双系统安装顺序和升级前的准备

Windows和Ubuntu双系统,最不容易出问题的安装顺序是先装Windows再装Ubuntu,让Ubuntu的安装程序自动识别并添加Windows的引导项。反过来装,Windows安装程序往往不客气地重写引导,让你只能先进Windows再想办法。

Windows大版本更新前,如果条件允许,建议先在Ubuntu里跑一次sudo update-grub,然后备份一下EFI分区的Ubuntu引导文件目录。真被Windows覆盖了,你也有备份可以直接恢复。当然,最简单粗暴但可靠的办法就是随时备一个Live启动U盘,出现问题十分钟内能进chroot修复。

6.3 分区调整后严格检查UUID

给Linux系统做分区调整,无论你用GParted、命令行parted还是Windows的磁盘管理,调整完第一件事不是重启,而是打开终端执行blkid,对比一下/etc/fstab里的UUID有没有变化。

很多人在GParted里把根分区往后挪了50GB空间,看着很顺利,重启就进grub>,这就是典型的UUID变化问题。如果分区的UUID变了,改完/etc/fstab和update-grub后记得再重启验证一次,不要觉得改完就万事大吉。

6.4 硬件层面的两个小检查

软件排查完了还是反复进grub>,那就该往硬件方向看一眼。最常见的是主板CMOS电池没电,导致每次断电后BIOS设置全部重置,启动顺序变回默认,GRUB启动项排在后面,自然进不去。换一颗纽扣电池,十几块钱的事,却能省下很多莫名其妙的排查时间。

另外一个是U盘或移动硬盘插着没拔。有些主板在启动时会优先从可移动设备引导,如果你插着一个含有引导文件的U盘,就会从一个不该引导的设备启动,或者卡在某个不完整的引导环境里。碰到开机进grub>先别急着怀疑系统,拔掉所有外置存储设备再重启一次,有时候问题就消失了。

我在实际维护中碰到grub>的次数不少,但真正需要重装系统的几乎没有。绝大多数时候,要么是grub.cfg丢失,要么是EFI启动项顺序被改,要么是/boot空间不足导致内核更新失败。掌握手动引导那一串命令之后,再遇到这种情况就不会慌了。修完之后别忘了做个全盘快照或者至少备份一下/boot/grub/grub.cfg,这个文件就是你开机时的那本“电话本”,备份好它,下次恢复能省一半时间。

RELATED READING

延伸阅读

更多一线实战笔记与深度复盘,助您持续精进