#!/bin/bash
#
# grub-menu-reorder.sh
#
# Purpose / 用途:
# Post-process /boot/grub/grub.cfg to rename top-level menu entries,
# reorder them according to a user-defined rank, and move the
# "Advanced options for Ubuntu" submenu to the bottom.
#
# 对 /boot/grub/grub.cfg 做后处理:重命名顶层菜单项,按用户
# 定义的优先级重排序,并把 "Advanced options for Ubuntu" 子菜单
# 移到底部。
#
# Why this exists / 为什么需要这个脚本:
# Ubuntu's 10_linux script hard-codes entry order and labels, and
# provides no supported configuration to change them. This script
# is a user-side workaround that operates on the generated file,
# not on the scripts themselves. It does NOT hijack /etc/grub.d/
# or replace any system script. It only rewrites grub.cfg after
# update-grub has run.
#
# Ubuntu 的 10_linux 脚本硬编码了菜单顺序和名称,没有提供任何
# 受支持的配置来修改它们。这个脚本是用户侧的变通方案,它只对
# 生成后的文件做处理,不碰 /etc/grub.d/ 下的脚本,也不替换任何
# 系统脚本。它只在 update-grub 运行之后重写 grub.cfg。
#
# What it does / 它做了什么:
# 1. Backs up grub.cfg before any modification.
# 2. Renames matching menu entries using a mapping table.
# 3. Reorders top-level entries according to a rank value.
# 4. Pushes "Advanced options for Ubuntu" to the bottom.
# 5. Validates the result with grub-script-check before replacing.
#
# 1. 修改前备份 grub.cfg。
# 2. 使用映射表重命名匹配的菜单项。
# 3. 按 rank 值重排顶层条目。
# 4. 把 "Advanced options for Ubuntu" 推到底部。
# 5. 用 grub-script-check 校验通过后再替换。
#
# This is a proof that the feature is implementable at the user
# level. It is not a substitute for a proper configuration mechanism
# in Ubuntu itself.
#
# 这证明了该功能在用户层面是可以实现的。它不能替代 Ubuntu 自身
# 应当提供的正规配置机制。
#
set -euo pipefail
GRUB_CFG=/boot/grub/grub.cfg
BACKUP="${GRUB_CFG}.hijack.bak"
LOG=/var/log/grub-hijack.log
RULES=/tmp/grub-hijack.rules
log() { echo "[$(date +%F\ %T)] $*" >> "$LOG"; }
RULES_ARR=(
"Ubuntu|Ubuntu|1"
"Windows Boot Manager (on /dev/sda1)|Windows|2"
"Restart|Restart|3"
"Shutdown|Shutdown|3"
"UEFI Firmware Settings|UEFI Firmware Settings|5"
"Advanced options for Ubuntu|Advanced options for Ubuntu|6"
)
[ -w "$GRUB_CFG" ] || { log "SKIP: not writable"; exit 0; }
cp -f "$GRUB_CFG" "$BACKUP" || { log "ERROR: backup failed"; exit 1; }
: > "$RULES"
for r in "${RULES_ARR[@]}"; do printf '%s\n' "$r" >> "$RULES"; done
if ! awk -v rules_file="$RULES" '
function title_of(ln, pre,t,q) {
pre = index(ln, SQ); if (pre==0) return ""
t = substr(ln, pre+1); q = index(t, SQ); if (q==0) return t
return substr(t, 1, q-1)
}
function rename_line(ln, newt, pre,rest,q) {
pre = index(ln, SQ); if (pre==0) return ln
rest = substr(ln, pre+1); q = index(rest, SQ); if (q==0) return ln
return substr(ln, 1, pre) newt substr(rest, q)
}
BEGIN {
SQ = sprintf("%c", 39)
blkpat = "^[ \t]*(menuentry|submenu) " SQ
n_rules = 0
while ((getline rl < rules_file) > 0) {
if (rl == "") continue
m = split(rl, f, "|"); if (m < 3) continue
n_rules++; old_a[n_rules]=f[1]; new_a[n_rules]=f[2]; rank_a[n_rules]=f[3]+0
}
close(rules_file)
fn = ARGV[1]; ARGV[1] = ""
c = 0
while ((getline line < fn) > 0) lines[++c] = line
close(fn)
nb = 0; seg = 0; i = 1; seg_start = 0
while (i <= c) {
if (lines[i] ~ /^### BEGIN \/etc\/grub.d\//) {
if (seg > 0) { nb++; b_start[nb]=seg_start; b_end[nb]=i-1;
b_title[nb]="(segment)" }
seg = 1; seg_start = i; i++; continue
}
if (lines[i] ~ /^### END \/etc\/grub.d\//) {
if (seg > 0) { nb++; b_start[nb]=seg_start; b_end[nb]=i;
b_title[nb]="(segment)"; seg=0 }
i++; continue
}
i++
}
if (seg > 0) { nb++; b_start[nb]=seg_start; b_end[nb]=c;
b_title[nb]="(segment)" }
nb2 = 0
for (b = 1; b <= nb; b++) {
adv = 0
for (k = b_start[b]; k <= b_end[b]; k++)
if (lines[k] ~ blkpat && title_of(lines[k]) ~ /^Advanced options/) { adv
= k; break }
if (adv > 0) {
nb2++; b2_start[nb2]=b_start[b]; b2_end[nb2]=adv-1;
b2_title[nb2]="(ubuntu-part)"
nb2++; b2_start[nb2]=adv; b2_end[nb2]=b_end[b]; b2_title[nb2]="Advanced
options for Ubuntu"
} else {
nb2++; b2_start[nb2]=b_start[b]; b2_end[nb2]=b_end[b];
b2_title[nb2]=b_title[b]
}
}
nb = nb2
for (b = 1; b <= nb; b++) { b_start[b]=b2_start[b]; b_end[b]=b2_end[b];
b_title[b]=b2_title[b] }
for (b = 1; b <= nb; b++) {
bt = b_title[b]
if (bt == "(segment)" || bt == "(ubuntu-part)") {
for (k = b_start[b]; k <= b_end[b]; k++)
if (lines[k] ~ blkpat) { bt = title_of(lines[k]); break }
if (bt == "") bt = "(segment)"
b_title[b] = bt
}
for (k = 1; k <= n_rules; k++) if (bt == old_a[k]) {
if (new_a[k] != old_a[k]) {
for (k2 = b_start[b]; k2 <= b_end[b]; k2++)
if (lines[k2] ~ blkpat) { lines[k2] = rename_line(lines[k2],
new_a[k]); break }
}
rk = rank_a[k]
if ((b in b_rank) == 0 || rk < b_rank[b]) b_rank[b] = rk
}
}
out_n = 0; done = 0
while (done < nb) {
minr = 999999
for (b = 1; b <= nb; b++)
if (cfg_out[b] == 0 && (b in b_rank) != 0 && b_rank[b] < minr) minr =
b_rank[b]
if (minr == 999999) break
for (b = 1; b <= nb; b++)
if (cfg_out[b] == 0 && (b in b_rank) != 0 && b_rank[b] == minr) {
out_n++; out[out_n]=b; cfg_out[b]=1; done++ }
}
for (b = 1; b <= nb; b++) if ((b in b_rank) == 0) { out_n++; out[out_n]=b }
for (o = 1; o <= out_n; o++) { b = out[o]; for (k = b_start[b]; k <=
b_end[b]; k++) print lines[k] }
}
' "$GRUB_CFG" > "${GRUB_CFG}.tmp"; then
log "ERROR: awk failed, restored"
cp -f "$BACKUP" "$GRUB_CFG"
rm -f "${GRUB_CFG}.tmp"
exit 1
fi
[ -s "${GRUB_CFG}.tmp" ] || {
log "ERROR: empty, restored"
cp -f "$BACKUP" "$GRUB_CFG"
rm -f "${GRUB_CFG}.tmp"
exit 1
}
grub-script-check "${GRUB_CFG}.tmp" >/dev/null 2>&1 || {
log "ERROR: syntax invalid, restored"
cp -f "$BACKUP" "$GRUB_CFG"
rm -f "${GRUB_CFG}.tmp"
exit 1
}
mv -f "${GRUB_CFG}.tmp" "$GRUB_CFG"
log "OK: done (rules: ${#RULES_ARR[@]})"
** Attachment added: "个人解决方案,但每次更新都被覆盖。"
https://bugs.launchpad.net/ubuntu/+source/grub2/+bug/2167721/+attachment/6001057/+files/grub-hijack.sh
--
You received this bug notification because you are a member of Ubuntu
Bugs, which is subscribed to Ubuntu.
https://bugs.launchpad.net/bugs/2167721
Title:
[Wishlist] Allow users to control GRUB top-level menu order and
content (Ubuntu / Windows / Restart / Shutdown / Advanced options)
To manage notifications about this bug go to:
https://bugs.launchpad.net/ubuntu/+source/grub2/+bug/2167721/+subscriptions
--
ubuntu-bugs mailing list
[email protected]
https://lists.ubuntu.com/mailman/listinfo/ubuntu-bugs