update-grub (Grub 2) (memtest86+) 上 grub.cfg 中的语法错误

don*_*ote 3 grub grub2

当我运行 update-grub 或尝试重新安装它时,出现“语法错误”。

输出有点像这样:

error: syntax error.
error: Incorrect command.
error: syntax error.
error: line no: 262
Syntax errors are detected in generated GRUB config file.
Ensure that there are no errors in /etc/default/grub
and /etc/grub.d/* files or please file a bug report with
/boot/grub/grub.cfg.new file attached.
Run Code Online (Sandbox Code Playgroud)

为什么会这样?我能做什么?

背景

在 Manjaro 更新后,我的系统不再启动。它说“/boot/vmlinuz-316-x86_64找不到文件”。然后“您需要先加载内核”。

然后我从 USB 记忆棒(manjaro live/安装程序磁盘)启动,并按照https://wiki.manjaro.org/index.php/Restore_the_GRUB_Bootloader(UEFI系统)中的说明使用 chroot 和 update-grub。事实上,在我尝试重新安装 grub 的步骤中,我首先注意到“语法错误”问题,因为我收到“此系统不支持 EFI 变量”。

我想(但不确定)这可能已经持续了一段时间而没有引起注意。对 grub.cfg 的任何更新都失败了,但旧的 grub.cfg 仍然“足够好”。但是随着更新,vmlinuz 文件被重命名,grub.cfg 引用了一个旧的,不再存在的 vmlinuz 文件。这就是启动失败的原因。


(我在写这篇的时候已经知道答案了。可能解释不完整,但我修复它已经足够了。我只是想分享结果,省去别人的麻烦)

don*_*ote 8

对我来说,这是一个非常具体的答案,但我想以更一般的方式解释如何解决这个问题。

实际上很多信息已经在错误消息中了,但对我来说一开始并不明显。

简而言之:

  • 按照行号,在 /boot/grub/grub.cfg.new 中。试着理解为什么你发现有语法错误。
  • 遵循此文件中的注释,该注释指向 /etc/default/grub 或 /etc/grub/* 中的特定文件。
  • 如果是代理脚本,请按照提示找到/etc/grub.d/proxifiedScripts/.

故障排除步骤,详细

/boot/grub/grub.cfg是在“更新grub的”自动创建的,基于大量的文件:/etc/default/grub和中的任何文件/etc/grub.d/*

/boot/grub/grub.cfg.new
但是,如果出现语法错误(或任何错误,我想),原始/boot/grub/grub.cfg文件不会被覆盖,而是在/boot/grub/grub.cfg.new.

错误消息包含一个行号,在我的例子中是 262,它指的是这个/boot/grub/grub.cfg.new文件。就我而言,这是 262。查看文件,我发现:

### BEGIN /etc/grub.d/60_memtest86+_proxy ###
if [ "${grub_platform}" == "pc" ]; then
fi
### END /etc/grub.d/60_memtest86+_proxy ###
Run Code Online (Sandbox Code Playgroud)

我了解到不允许在 shell 脚本中使用空的 if/then/fi 块,所以这是语法错误。很愚蠢的语言设计imo,但事实就是这样。

我还找到了一个修复方法,就是在块中添加一个无意义的语句。建议使用冒号,但可能还有其他解决方案。

### BEGIN /etc/grub.d/60_memtest86+_proxy ###
if [ "${grub_platform}" == "pc" ]; then
    :
fi
### END /etc/grub.d/60_memtest86+_proxy ###
Run Code Online (Sandbox Code Playgroud)

更好的是完全删除这个无意义的块。

现在我们真的不想手动编辑这个文件,因为更改将在下一次 update-grub 中被擦除(如果成功,这就是目标)。

/etc/grub.d/*
代码片段包含下一步要查看的提示:/etc/grub.d/60_memtest86+_proxy. 这个文件说:

#!/bin/sh
#THIS IS A GRUB PROXY SCRIPT
'/etc/grub.d/proxifiedScripts/memtest86+' | /etc/grub.d/bin/grubcfg_proxy "+*
+#text
-'Memory Tester (memtest86+)'~30b99791e52c3f0cb32601c5b8f57cc7~
"
Run Code Online (Sandbox Code Playgroud)

/etc/grub.d/proxifiedScripts/*
的相关部分/etc/grub.d/proxifiedScripts/memtest86+是这样的:

    [..]
    cat << EOF
if [ "\${grub_platform}" == "pc" ]; then
    menuentry "Memory Tester (memtest86+)" ${CLASS} {
        search --fs-uuid --no-floppy --set=root ${_GRUB_MEMTEST_HINTS_STRING} ${_GRUB_MEMTEST_FS_UUID}
        linux16 ${_GRUB_MEMTEST_REL_PATH} ${GRUB_CMDLINE_MEMTEST86}
    }
fi
EOF
[..]
Run Code Online (Sandbox Code Playgroud)

该文件本身是一个 shell 脚本,但它有那些“cat”语句。这些打印最终应该进入的 shell 脚本片段/boot/grub/grub.cfg。经过一些修改,也许。

在 中/boot/grub/grub.cfg.new,我们观察到“menuentry ...”的东西实际上丢失了,取而代之的是一个空的 then..fi 块。为什么“menuentry ...”消失了,我不知道。也许 grub 认为不需要它。不幸的是,删除破坏了脚本。

解决方法

技巧/解决方法是在此文件中添加一个冒号,如下所示:

if [ "\${grub_platform}" == "pc" ]; then
    :
    menuentry "Memory Tester (memtest86+)" ${CLASS} {
        search --fs-uuid --no-floppy --set=root ${_GRUB_MEMTEST_HINTS_STRING} ${_GRUB_MEMTEST_FS_UUID}
        linux16 ${_GRUB_MEMTEST_REL_PATH} ${GRUB_CMDLINE_MEMTEST86}
    }
Run Code Online (Sandbox Code Playgroud)

运行 update-grub 时,这会生成grub.cfg具有上述解决方法的 。

背景/更多调查

/etc/grub.d/我系统上的文件夹实际上包含 memtest86+_proxy:60_memtest86+_proxy62_memtest86+_proxy. 我认为其中一个是某种剩余物。但是它们都有相同的更新时间戳,所以我真的不知道删除哪个可以安全。差异显示了这一点:

--- /etc/grub.d/60_memtest86+_proxy 2015-01-08 15:54:02.228927526 +0100
+++ /etc/grub.d/62_memtest86+_proxy 2015-01-08 15:54:02.228927526 +0100
@@ -1,6 +1,6 @@
 #!/bin/sh
 #THIS IS A GRUB PROXY SCRIPT
-'/etc/grub.d/proxifiedScripts/memtest86+' | /etc/grub.d/bin/grubcfg_proxy "+*
-+#text
--'Memory Tester (memtest86+)'~30b99791e52c3f0cb32601c5b8f57cc7~
+'/etc/grub.d/proxifiedScripts/memtest86+' | /etc/grub.d/bin/grubcfg_proxy "+'Memory Tester (memtest86+)'~30b99791e52c3f0cb32601c5b8f57cc7~
+-*
+-#text
 "
\ No newline at end of file
Run Code Online (Sandbox Code Playgroud)

因此,这两个文件都引用了相同的代理脚本,但结果是通过 grubcfg_proxy 二进制文件通过管道传输的,具有不同的参数。这些不同的参数可能负责在60_memtest86+_proxy.

结论

其他人可能有完全不同的问题。但是故障排除,至少是第一步,应该非常相似。