如何将GRUB重新安装到EFI分区?

我想重新安装GRUB 2,并找到了以下的指示: 如何使用Ubuntu Live CD或USB修复、恢复或重新安装Grub 2。 在我的情况下,引导加载程序已安装在EFI分区中。如果我按照这个指南提供的命令操作,GRUB会自动重新安装到EFI分区吗?还是会安装到Ubuntu所在的根分区?显然,我不希望发生后者。

7提供的链接中的说明仅适用于在传统BIOS模式下重新安装GRUB,对于您的情况不起作用。要在EFI BIOS模式下重新安装GRUB到Ubuntu安装,请阅读我的答案。 :) - cl-netbox
非常感谢!:) 我有一些问题:当我在我的UEFI系统中安装Ubuntu时,我在BIOS中发现了两个条目。有没有办法只有一个Ubuntu条目? 如果使用MBR分区表(没有EFI或其他引导分区),我可以使用相同的命令吗,除了:sudo mount /dev/sd** /mnt/boot/efi? - Generoso
你可以尝试使用以下命令删除第二个Ubuntu条目:sudo efibootmgr(列出所有条目)| sudo efi bootmgr -b <entry-number> -B.... 并且要在传统BIOS模式下重新安装GRUB,请执行以下命令:sudo mount /dev/sd** /mnt | sudo grub-install --boot-directory=/mnt/boot /dev/sd表示磁盘| **表示系统分区)! :) - cl-netbox
完美 :) 无论如何,如果我有一个UEFI系统和一个EFI分区,是否有办法在进行新的Windows安装时避免grub被覆盖? - Generoso
嗯,微软只关心自己的产品,所以你可以安装Linux系统而不会对Windows造成任何伤害 - 不幸的是反过来就不行了 - 所以当你在安装Ubuntu之后安装Windows时,你必须在之后恢复GRUB引导加载程序。 :) - cl-netbox
清楚 :) 无论如何,我尝试使用efibootmgr删除第二个Ubuntu条目(指grubx64.efi),但当我重新启动计算机时,它又出现了!相反,如果我尝试删除其他条目(即指shimx64.efi),就没有问题。然而,当我在BIOS中选择Ubuntu时,它奇怪地成功加载。我之所以说奇怪,是因为我读到,当安全启动处于活动状态时,我必须选择指向shimx64.efi的条目才能正确加载Ubuntu!我有点困惑.. - Generoso
你所读的是正确的,当启用安全启动时,你使用shimx64引导,当禁用安全启动时,你使用grubx64引导。这样可以给你两个选项,所以我的建议是保持现状就好。 :) - cl-netbox
好的 :) 那我会重新命名BIOS条目,这样我就可以区分它们并根据安全启动状态选择合适的条目 :) 有没有一个命令可以恢复我之前删除的(shimx64)条目呢? :D - Generoso
执行:sudo efibootmgr -c -w -d /dev/sd* -p 1 -L "ubuntu" -l '\EFI\ubuntu\shimx64.efi'(* = 磁盘):) - cl-netbox
在我看来,BIOS和EFI之间的区别很难轻松应对。最好选择其中一个。 - user595510
1所有当前的答案都使用了chroot,但在我的机器上没有起作用(我无法在chroot内访问我的驱动器),所以我添加了一个不需要chroot的解决方案:https://askubuntu.com/a/1203713/541576 - Gabriel Devillers
13个回答

重新以EFI模式将GRUB引导加载程序安装到您的Ubuntu安装中... 从Ubuntu安装介质引导并选择“试用Ubuntu而不安装”。 (以EFI模式引导安装介质,选择前面带UEFI标志的Ubuntu条目。)
一旦进入实时桌面,打开终端并执行以下命令:
sudo mount /dev/sdXY /mnt
sudo mount /dev/sdXX /mnt/boot/efi 

for i in /dev /dev/pts /proc /sys /run; do sudo mount -B $i /mnt$i; done  

sudo chroot /mnt  

grub-install /dev/sdX
update-grub
exit  

注意:如果 grub-install 命令报告错误,找不到 efivars,请尝试在 chroot 环境中执行以下操作(感谢 @michael_dunn - 在 Ubuntu 22.10 中这一步是必需的):
mount -t efivarfs none /sys/firmware/efi/efivars  

之后再次执行grub-install命令:grub-install /dev/sdX
为避免可能的意外问题,请适当卸载文件系统。
sudo umount /dev/sdXX
sudo umount /dev/sdXY

注意: sdX = 磁盘 | sdXX = efi 分区 | sdXY = 系统分区
要识别分区,请使用 GParted 工具,该工具已包含在安装介质中。 运行命令后,GRUB 将安装在单独的 EFI 分区中。

3+1 但为什么不直接从Ubuntu官方安装呢? - user595510
3@MarkYisri:非常感谢!:) 这是最安全的方法,可以重新安装GRUB引导加载程序而不会损坏其他东西,并且在系统无法正常启动的情况下...这是唯一的方法!:) - cl-netbox
更换了一个英特尔NUC后,新设备无法从旧硬盘启动。这个方法解决了问题。你让我开心得不得了 - 非常感谢! - Möhre
6在这个解决方案中,'grub-install' 如何知道它应该安装在 EFI 模式下? - user334639
@user334639 这是因为EFI分区会自动识别... :) - cl-netbox
谢谢!这是因为磁盘采用GPT格式而不是MBR格式,对吗?将MBR转换为GPT会是一个不同的问题,对吗? - user334639
1一般来说,现代机器上基于EFI的BIOS系统安装会部署在采用GPT分区表的磁盘上,而旧机器上基于MBR的BIOS系统安装则会部署在采用"msdos"分区表的磁盘上。当GRUB引导加载程序被安装时,这将自动检测到...在传统BIOS模式下的系统安装中,不存在EFI分区。 :) - cl-netbox
17重要的是以正确的引导模式启动安装介质,如果我们想要重新安装 grub-efi,我们必须以UEFI模式启动;如果我们想要重新安装 grub-pc,我们必须以传统模式启动。 - mook765
@mook765 感谢你的贡献!虽然这应该是一个显而易见的事实,但我认为你提供的信息很有用,尤其对于不太有经验的用户来说。因此,我决定将它包含在答案中。 :) - cl-netbox
嗨,谢谢你的帖子。当你说“ sdXXX = 系统分区”时,你是指分配给 //home 还是 /boot 的分区?谢谢。 - Chris Rogers
嗨@ChrisRogers,不用谢!:) sdXXX是系统分区,意思是:/(根分区)。 - cl-netbox
太棒了,谢谢你。 - Chris Rogers
1安装Ubuntu 18.04时,只有grub-pc可用。首先运行sudo apt-get install grub-efi,然后按照以下步骤进行操作。在运行grub-install时仍然收到错误消息,但忽略它并运行update-grub,该命令找到了Windows的EFI。然后我不得不重新启动,进入引导管理界面,并更新引导顺序选项。尽管它没有列出来,但它给了我添加引导选项的选项,然后搜索文件,在正确的文件系统+ EFI目录中找到了它。将新的引导选项设置为第一项,最终成功了! - iisisrael
4这对我来说有效,只是有一个改动:我使用了grub-install /dev/sdXX,即不是磁盘而是EFI分区用于安装grub,它起作用了。 - Duck Dodgers
我认为如果你这样做: 1)在清除Windows分区之后, 2)在/etc/fstab中使用UUID来识别分区, 你至少需要更新/etc/fstab中的/boot/efi UUID(确保其他也是正确的)。你可以使用blkid命令找到分区ID。 - Egor Tensin
32位版本呢? - chx101
这真的帮了我大忙。我一直在网上搜寻解决办法。 - wesley franks
谢谢这个解决方案,它起作用了。我想补充一下,在操作后我遇到了启动时间长的问题(大约3分钟系统启动)。我不得不更新/etc/fstab文件中efi分区的正确UUID。只需比较sudo blkid命令获取的efi分区的UUID和/etc/fstab文件中的UUID即可。 - user634093
有人能给我解释一下第三条命令for i in /dev /dev/pts /proc /sys /run; do sudo mount -B $i /mnt$i; done的作用吗? - kamer_kane
1@Vivek 它将 /dev /dev/pts /proc /sys /run 从实时系统绑定到已安装的系统上,这样你在实时系统上执行的命令就可以有效地对已安装的系统进行更改。这是上述命令的简化版本: sudo mount -o bind /dev /mnt/dev sudo mount -o bind /dev/pts /mnt/dev/pts sudo mount -o bind /proc /mnt/proc sudo mount -o bind /run /mnt/run sudo mount -o bind /sys /mnt/sys - cl-netbox
在我的情况下,grub-install 步骤失败并显示“只读分区”。因此,我退出了 chroot 环境,卸载了 efi 分区,然后使用 --rw 重新挂载它。再次进入 chroot 环境,重新安装成功。这是在 Ubuntu 20.04 的 live CD 上进行的操作。 - EugeneRomero
在Ubuntu 20.04上运行良好,只需执行以下操作:删除所有Windows分区,移动Ubuntu分区并格式化EFI分区。谢谢! - NicolasSmith
非常感谢您的回答。+1 - schizoid_man
2您先生是一位上帝,一个点赞远远不足以偿还。 - rchurch4
@cl-netbox 你好,我按照你说的步骤进行操作,但是当我执行 grub-install /dev/sda 的时候,它花费的时间太长了...现在已经超过5个小时了,我该怎么办?停止它吗?注意:我之前不小心删除了 EFI 分区。 - Rohit Nishad
嗨@RohitNishad :) EFI分区是让任何操作系统能够启动的必需品。EFI分区应该是磁盘上的第一个分区,并且必须使用FAT(fat32)格式进行格式化。通过从安装介质引导,使用GParted重新创建分区...如果您不确定如何执行所有操作,可能更容易的方法是完全重新安装Ubuntu操作系统。 - cl-netbox
我不知道为什么我的基于Debian的PVE在停电后无法启动(UEFI失败,没有GRUB界面),这真的救了我的命。 - yurenchen
我之前有一些“不好”的设置导致grub无法正常工作,而重新安装grub只是使用了相同的设置。在运行update-grub之前,我编辑了/etc/defaults/grub文件并删除了这些不好的设置。我不能百分之百确定它是如何找到非默认的grub文件的——在非chroot环境下,它具有正常的默认设置,但在chroot终端窗口中,我看到了我的“不好”的设置。 - Tim Coker
这种方法甚至在出现“检测到锁定的ESP”错误时也能帮助解决问题。随后,通过BIOS的协助进行了进一步的引导修复:AMI BIOS提出修复EFI数据库错误的建议。 - Oleg Kokorin
1这对我起作用的方式有2个修改:在chroot之后: mount -t efivarfs none /sys/firmware/efi/efivars 和 grub-install /dev/sdXX - michael_dunn
虽然现在不在我面前,但我记得在某个救援光盘的手册中读到过关于这个问题的解决方案,或者非常相似的解决方案。在那里强调了正确卸载文件系统的重要性。显然,在没有正确卸载的情况下重新启动,会对这些关键分区造成不可忽视的损坏风险,可能给引导过程带来新的、更难解决的障碍。鉴于这个答案的普及度,我在这里也会包含卸载部分的代码块。 - Levente
感谢你的建议 @Levente!虽然这是一个常见的做法,但我还是加上了卸载文件系统的部分。嗯,你说得对...安全起见,还是多一事不如少一事。 :) - cl-netbox
我应该期望它显示"umount: /mnt: target is busy"多久?如果它一直这样做,是否表示存在其他问题?(在我的具体情况下,Ubuntu在多次尝试重新安装后无法启动) - KernelDeimos
1@KernelDeimos:正如你所说的,“在多次尝试全新安装后Ubuntu无法启动”...是的,你肯定面临着其他问题。 - cl-netbox
@cl-netbox 原来我不得不将ubuntu/boot/grubx64.efi重命名为Microsoft/Boot/bootmfgw.efi或类似的名称... 这真是令人不舒服和奇怪。 - KernelDeimos
为什么我已经可以直接启动最终的Ubuntu系统,还需要从安装介质启动呢?谢谢。 - ying
@ying :你问:“从安装介质启动的原因是什么?”首先,主要原因是这是重新安装GRUB引导加载程序最安全的方式。其次,大多数用户只有在无法启动已安装的系统时才需要重新安装引导加载程序...还有,当一切正常时,为什么还会有人想要重新安装引导加载程序呢?:) - cl-netbox

这是对我有效的唯一方法: (系统:sdb8,引导:sdb6,efi:sdb2)
sudo mount /dev/sdb8 /mnt 
sudo mount /dev/sdb6 /mnt/boot 
sudo mount /dev/sdb2 /mnt/boot/efi

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

sudo chroot /mnt

grub-install --target=x86_64-efi /dev/sdb

grub-install --recheck /dev/sdb

exit &&
sudo umount /mnt/sys &&
sudo umount /mnt/proc &&
sudo umount /mnt/dev/pts &&
sudo umount /mnt/dev &&
sudo umount /mnt

1--recheck是什么作用?手册上说如果设备映射已经存在,则删除它。 - MrCalvin
如果我将启动项命名为与默认值不同的任何其他名称,例如--bootloader-id=Ubuntu_02,那么启动就会失败。它只会引导到grub控制台...有解决方法吗? - MrCalvin
是的,似乎需要运行grub-install --recheck命令。这个命令修复了我无法工作的USB硬盘驱动器的EFI问题。 - solsTiCe
1值得注意的是,要使 --target=x86_64-efi 选项生效,您需要一个名为 grub-efi-amd64-bin 的软件包。 - Hi-Angel
希望看到一份添加了一些“for”循环的修订版。 - AveryFreeman

这是我在标准的x86_amd64 EFI桌面上的操作方法,不需要chroot,假设你的硬盘上有一个包含Ubuntu的分区,可能还有一个应该安装GRUB的EFI分区。
# boot on a live Ubuntu, I used 18.04 but more recent should work

# if you have currently no EFI partition (maybe it was deleted,
# or you are migrating to a new drive):
# sudo gparted
# - create a FAT 32 partition of around 100 MB on the disk of your choice
# (in general the one that host the Ubuntu partition). If you plan to
# move or resize some paritions, anticipate that (for instance by
# creating the EFI partition at the end of the free space).
# - set the flag esp on this partition (the flag boot will also be selected)

# now assuming that the Ubuntu partition is `/dev/sda2` and the (possibly new) EFI partition is `/dev/sda1`
sudo apt install grub-efi
sudo mkdir /media/root && sudo mount /dev/sda2 /media/root
sudo mkdir /media/efi && sudo mount /dev/sda1 /media/efi
sudo grub-install --target=x86_64-efi /dev/sda --efi-directory=/media/efi --boot-directory=/media/root/boot

这应该是:

正在为 x86_64-efi 平台安装。

安装完成。未报告任何错误。

然后重新启动,你就完成了。你可能需要告诉你的BIOS使用哪个驱动器,或者使用哪个EFI分区,或者使用哪个EFI二进制文件。

如果你创建了一个新的EFI分区,你可能需要将其添加到/etc/fstab中,以使update-grub正常工作。

更多信息请参考:https://wiki.archlinux.org/index.php/Multiboot_USB_drive#Hybrid_UEFI_GPT_+_BIOS_GPT/MBR_boot


1谢谢你的建议。我使用了这个修改。由于我正在将虚拟机从BIOS转换为EFI,我只是用命令mkfs -t vfat /dev/sda2(在我的情况下!)将现有的/boot分区从ext格式格式化为fat格式,然后挂载它到/mnt/boot/,同时也挂载了我的根目录(LVM)。我将grub-install --force --target=x86_64-efi --boot-directory=/mnt/boot --efi-directory=/mnt/boot /dev/sda命令中的两个目录选项都指向同一个位置。然后,我编辑了挂载在/mnt/root/etc/fstab的fstab文件,并将UUID替换为/dev/sda2 + vfat/dev/mapper/..用于LVM。 <继续> - LuxZg
1不管怎样,在(成功!!!)重新启动之后,我仍然在操作系统(虚拟机)内部重复了一遍,通过运行 grub-install /dev/sda --efi-directory=/boot + update-grub + 另一次重新启动。我通过安装另一个内核并强制执行 update-grub 进行了测试,一切都很好,grub 文件被正确更新,并为该内核创建了新的条目。所以再次非常感谢你,干杯! - LuxZg
我在Serverfault上的Ubuntu虚拟机特定案例答案:https://serverfault.com/a/1047507/574185 - LuxZg
帮了很大的忙。我的系统中的磁盘还好,但容量已经接近极限。所以我把所有数据都转移到了新的磁盘上(使用btrfs send/receive命令),创建了新的EFI分区,复制了旧EFI的内容,并按照您的指示进行操作。然后在用新的磁盘重新启动后,我发现grub-install创建的grub.cfg引用了位于/boot/grub(位于btrfs分区上)的grub.cfg。这个文件中仍然包含之前磁盘的UUID,导致无法启动。我在那里修复了UUID(使用ls -l /dev/disk/by-uuid命令找到新的UUID),现在一切都正常了。谢谢! - Patrick Echterbruch
我给这个点了赞,但发现说明中缺少了update-grub这一步骤,我认为这是这个解决方案最大的缺陷,因为update-grub通常是大多数人不能错过的关键步骤(而且我猜它必须在chroot环境中完成)。 - xpt

在过去的几个月里,涉及到的库进行了一些更新。
以下步骤对我很有帮助。它们汲取了旧答案和其他论坛的想法。
确保您使用EFI引导。
efibootmgr -v

运行 grub-install
sudo mount /dev/nvme0n1p5 /mnt 
sudo mount /dev/nvme0n1p1 /mnt/boot/efi

for i in /dev /dev/pts /proc /sys /sys/firmware/efi/efivars /run; do sudo mount -B $i /mnt$i; done

sudo chroot /mnt

grub-install --target=x86_64-efi /dev/nvme0n1
grub-install --recheck /dev/nvme0n1

# as a second attempt, you could also try (assuming _debian_ is your distro)
# grub-install --target=x86_64-efi --efi-directory=/boot/efi --bootloader-id=debian
# grub-mkconfig -o /boot/grub/grub.cfg

update-grub2

exit &&
sudo umount /mnt/sys &&
sudo umount /mnt/proc &&
sudo umount /mnt/dev/pts &&
sudo umount /mnt/dev &&
sudo umount /mnt

确保 efibootmgr 将您的 Linux 列为一个条目

efibootmgr -v

感谢@cl-netbox的指导!

升级后(从Linux Mint 18.2 Sonya 到18.3 Sylvia),我的系统无法启动,所以我遵循上述说明,但仍然没有成功。不过我注意到我的机器有/boot在单独的分区(可能是因为我使用了LVM),所以我稍微修改了一下流程:

sudo mount /dev/sdXXX /mnt
sudo mount /dev/sdXY /mnt/boot
sudo mount /dev/sdXX /mnt/boot/efi
for i in /dev /dev/pts /proc /sys /run; do sudo mount -B $i /mnt$i; done
sudo chroot /mnt
grub-install /dev/sdX
update-grub 

注意:sdX = 磁盘 | sdXX = efi 分区 | sdXY = 引导分区 | sdXXX = 系统分区

1我在一台正在运行的Ubuntu Bionic系统上不小心执行了rm -Rf /boot/efi命令!我的系统仍然在运行,所以我尝试使用了最后两个命令(grub-install /dev/mapper/ubuntu--vg-root和update-grub)。重新启动后,一切都完美地工作了。太好了,谢谢 :) - Roel Van de Paar
使用LVM,开始的步骤应该是这样的:sudo vgchange -ay name_of_:the_lvg,然后再运行sudo mount /dev/sname_of_:the_lvg/root /mnt。 - Benjamin Hastings

此外,如果从光盘启动以进行恢复,可能会出现缺少 grub-efi-amd64-bin 软件包的情况。
"grub-install --target=x86_64-efi /dev/sdb" 

在这种情况下,运行以下命令以解决错误信息:"grub-install: error: /usr/lib/grub/x86_64-efi/modinfo.sh不存在。请指定--target或--directory。"请在chroot之外运行此命令。
sudo apt get grub-efi-amd64-bin

然后将 /usr/lib/grub/x86_64-efi 添加到 chroot 挂载中。
顺便说一句,"/dev/sdb" 参数已经过时并被忽略。

我想知道sudo apt get grub-efi-amd64-bin会做什么。 - mook765
sudo apt get grub-efi-amd64-bin 不是一个有效的命令。也许你的意思是 sudo apt install ... - Organic Marble

如果你不小心丢失了EFI分区,那么很容易恢复它。你可以使用诸如fdiskparted之类的分区工具来创建一个新的分区sdXY(例如sda1),类型为“EFI分区(1)”,并用以下格式进行格式化:
sudo mkfs.msdos /dev/sdXY

然后使用以下命令挂载它:
sudo mount /dev/sdXY /boot/efi

你可以通过运行以下命令重新安装GRUB:
sudo grub-install --efi-directory=/boot/efi

根据其他解决方案提到。

1你肯定是在磁盘上格式化一个分区,比如/dev/sdX1,而不是整个块设备吧? - Josip Rodin

我不能评论(声望不够),但@Chilu Pereira的答案是在EFI或多启动情况下的正确方法。这与gentoo指南中的方法类似。 他们使用了稍微不同的方法: 不是使用mount --bind,而是使用mount --rbind,然后对sys和dev使用mount --make-rslave,proc只需重新挂载即可。 在gentoo中,我过去会像这样从一个实时系统创建挂载点:
mount -t proc /proc /mnt/proc
mount --rbind /sys /mnt/sys
mount --make-rslave /mnt/sys
mount --rbind /dev /mnt/dev
mount --make-rslave /mnt/dev 
chmod 1777 /mnt/dev/shm

有人知道--bind--rbind / --make-rslave之间的确切区别吗?
但是今天我在grub2的chroot中遇到了两个错误,这是我以前从未遇到过的:
 connect: No such file or directory
   Please make sure that the zfs-fuse daemon is running

并且

grub-install: warning: Cannot read EFI Boot* variables.
grub-install: warning: read_file: could not read from file: Input/output error.

zfs-fuse的错误似乎无关紧要,但对于Efivars,我不得不再添加一个挂载点。
mount --bind /sys/firmware/efi/efivars /mnt/sys/firmware/efi/efivars

我猜在chroot中/sys/firmware/efi/efivars不存在,或者可能是只读的 - 不过无论如何它都起作用了。

同意,那个答案修复了我的 grub 安装,而不会破坏现有的 Apple 分区(我认为不需要绑定挂载 /dev/pts)。 - Z4-tier
/dev/pts 这个东西在很多教程和手册中都能找到。由于 /dev/pts 是伪终端和绑定挂载,可能并不需要它。 - schiffsratte
1我刚刚找到了一个解释,为什么你应该优先选择--rbind而不是--bind,因为--rbind可以访问在你创建的绑定挂载下面的其他绑定挂载。这里有一个更好的解释:[https://askubuntu.com/a/1188621/260981] - schiffsratte
我猜 'r' 是指递归。我还没听说过那个选项。我一时想不起来在 '/sys' 下是否有其他挂载点,但如果有的话,我希望 'rbind' 能检测到循环! - Z4-tier

除了ci-netbox的答案之外。
如果您的U盘操作系统版本与磁盘上安装的版本不匹配,grub-install可能会难以识别正确的grub安装:
$ sudo chroot /mnt
# grub-install /dev/sdX
grub-install: error: /usr/lib/grub/i386-pc/modinfo.sh doesn't exist. 
Please specify --target or --directory.

尝试手动识别要使用的安装程序
# ls /usr/lib/grub/
grub-mkconfig_lib  x86_64-efi  x86_64-efi-signed

然后重新启动 grub-install:
# grub-install --target=x86_64-efi /dev/sdX 
Installing for x86_64-efi platform.
Installation finished. No error reported.

这个花了我一些时间来完成。我的设置和你一样(非加密的/boot,另外还有一个vfat的/boot/efi)。下面的Debian指南解决了问题。其他所有指南都缺少挂载efivars以及完整的grub重新安装步骤等内容。希望对你有所帮助!

https://wiki.debian.org/GrubEFIReinstall

以下是其他答案中缺少的具体细节:
  • 在chroot中安装grub时,包括efivars

    for i in /dev /dev/pts /proc /sys /sys/firmware/efi/efivars /run; do sudo mount -B $i /mnt$i; done
    
  • 不要忘记在chroot中挂载/boot/boot/efi

  • 运行所有的grub命令

    apt-get install --reinstall grub-efi
    grub-install /dev/disk
    update-grub
    
感谢debian!