Как вывести список "пунктов меню" GRUB в командной строке?

Есть ли способ получения списка названий "menuentries" GRUB?

Мне нужны результаты в формате, который grub-set-default приму. например.

"Ubuntu"
"Memory test (memtest86+)"
etc.

9 ответов

Решение

С помощью awk

awk -F\' '/menuentry / {print $2}' /boot/grub/grub.cfg 

дает вам полный список всех пунктов меню в grub.cfg,

Цветной снимок экрана (короткая версия)

Используйте колесо прокрутки мыши, клавиши Home, End, PgUp, PgDn, и для навигации по меню.

Снимок экрана с текстом (длинная версия)

Скрипт bash использует whiptail вместо dialog для отображения меню. Одним из преимуществ является то, что вы можете скопировать изображение терминала в буфер обмена в виде текста и вставить его на этот сайт в виде текста. Другие преимущества включают в себя:

  • Поддержка колеса прокрутки мыши
  • Быстрее производительность
  • dialog не устанавливается по умолчанию в Ubuntu Server или Lubuntu. whiptail включен по умолчанию.

Вот текстовый снимок экрана:

Grub Version: 2.02~beta2-36ubuntu3.15


        ┌─────────┤ Use arrow, page, home & end keys. Tab toggle option ├──────────┐
        │ Menu No. --------------- Menu Name ---------------                       │ 
        │                                                                          │ 
        │     0    Ubuntu                                                     ↑    │ 
        │     1    Advanced options for Ubuntu                                ▮    │ 
        │     1>0  Ubuntu, with Linux 4.14.31-041431-generic                  ▒    │ 
        │     1>1  Ubuntu, with Linux 4.14.31-041431-generic (upstart)        ▒    │ 
        │     1>2  Ubuntu, with Linux 4.14.31-041431-generic (recovery mode)  ▒    │ 
        │     1>3  Ubuntu, with Linux 4.14.30-041430-generic                  ▒    │ 
        │     1>4  Ubuntu, with Linux 4.14.30-041430-generic (upstart)        ▒    │ 
        │     1>5  Ubuntu, with Linux 4.14.30-041430-generic (recovery mode)  ▒    │ 
        │     1>6  Ubuntu, with Linux 4.14.27-041427-generic                  ▒    │ 
        │     1>7  Ubuntu, with Linux 4.14.27-041427-generic (upstart)        ▒    │ 
        │     1>8  Ubuntu, with Linux 4.14.27-041427-generic (recovery mode)  ▒    │ 
        │     1>9  Ubuntu, with Linux 4.14.24-041424-generic                  ▒    │ 
        │     1>10 Ubuntu, with Linux 4.14.24-041424-generic (upstart)        ▒    │ 
        │     1>11 Ubuntu, with Linux 4.14.24-041424-generic (recovery mode)  ▒    │ 
        │     1>12 Ubuntu, with Linux 4.14.23-041423-generic                  ▒    │ 
        │     1>13 Ubuntu, with Linux 4.14.23-041423-generic (upstart)        ↓    │ 
        │                                                                          │ 
        │                                                                          │ 
        │                   <Display Grub Boot>        <Exit>                      │ 
        │                                                                          │ 
        └──────────────────────────────────────────────────────────────────────────┘ 

Выделите запись и нажмите Enter

Используйте клавиши навигации, чтобы выделить опцию, и нажмите Enter, чтобы увидеть драйверы перед ядром, загруженные grub и параметры загрузки передаются grub в ядро ​​при загрузке:

menuentry 'Ubuntu, with Linux 4.14.27-041427-generic' --class ubuntu --class gnu-linux --class gnu --class os $menuentry_id_option 'gnulinux-4.14.27-041427-generic-advanced-f3f8e7bc-b337-4194-88b8-3a513f6be55b' {
recordfail
savedefault
load_video
gfxmode $linux_gfx_mode
insmod gzio
if [ x$grub_platform = xxen ]; then insmod xzio; insmod lzopio; fi
insmod part_gpt
insmod ext2
if [ x$feature_platform_search_hint = xy ]; then
search --no-floppy --fs-uuid --set=root f3f8e7bc-b337-4194-88b8-3a513f6be55b
else
search --no-floppy --fs-uuid --set=root f3f8e7bc-b337-4194-88b8-3a513f6be55b
fi
echo 'Loading Linux 4.14.27-041427-generic ...'
linux /boot/vmlinuz-4.14.27-041427-generic root=UUID=f3f8e7bc-b337-4194-88b8-3a513f6be55b ro quiet splash loglevel=0 vga=current udev.log-priority=3 fastboot kaslr acpiphp.disable=1 crashkernel=384M-2G:128M,2G-:256M $vt_handoff
echo 'Loading initial ramdisk ...'
initrd /boot/initrd.img-4.14.27-041427-generic
}
Press <Enter> to continue

grub-menu.sh скрипт bash

grub-menu.sh есть только один вариант настройки:

# Default for hide duplicate and triplicate options with (upstart) and (recovery mode)?
HideUpstartRecovery=false

Установите значение true (скрыть лишние записи) или false (перечислить все записи).

Формат по умолчанию может быть переопределен при вызове скрипта с использованием:

grub-menu.sh short

или же:

grub-menu.sh long

Код:

#!/bin/bash

# NAME: grub-menu.sh
# PATH: $HOME/bin
# DESC: Written for AU Q&A: https://Ask-ubuntu.ru/q/1019213/307523
# DATE: Apr 5, 2018. Modified: May 7, 2018.

# $TERM variable may be missing when called via desktop shortcut
CurrentTERM=$(env | grep TERM)
if [[ $CurrentTERM == "" ]] ; then
    notify-send --urgency=critical "$0 cannot be run from GUI without TERM environment variable."
    exit 1
fi

AllMenusArr=()      # All menu options.
# Default for hide duplicate and triplicate options with (upstart) and (recovery mode)?
HideUpstartRecovery=false
if [[ $1 == short ]] ; then
    HideUpstartRecovery=true    # override default with first passed parameter "short"
elif [[ $1 == long ]] ; then
    HideUpstartRecovery=false   # override default with first passed parameter "long"
fi
SkippedMenuEntry=false  # Don't change this value, automatically maintained
InSubMenu=false     # Within a line beginning with `submenu`?
InMenuEntry=false   # Within a line beginning with `menuentry` and ending in `{`?
NextMenuEntryNo=0   # Next grub internal menu entry number to assign
# Major / Minor internal grub submenu numbers, ie `1>0`, `1>1`, `1>2`, etc.
ThisSubMenuMajorNo=0
NextSubMenuMinorNo=0
CurrTag=""          # Current grub internal menu number, zero based
CurrText=""         # Current grub menu option text, ie "Ubuntu", "Windows...", etc.
SubMenuList=""      # Only supports 10 submenus! Numbered 0 to 9. Future use.

while read -r line; do
    # Example: "           }"
    BlackLine="${line//[[:blank:]]/}" # Remove all whitespace
    if [[ $BlackLine == "}" ]] ; then
        # Add menu option in buffer
        if [[ $SkippedMenuEntry == true ]] ; then
            NextSubMenuMinorNo=$(( $NextSubMenuMinorNo + 1 ))
            SkippedMenuEntry=false
            continue
        fi
        if [[ $InMenuEntry == true ]] ; then
            InMenuEntry=false
            if [[ $InSubMenu == true ]] ; then
                NextSubMenuMinorNo=$(( $NextSubMenuMinorNo + 1 ))
            else
                NextMenuEntryNo=$(( $NextMenuEntryNo + 1 ))
            fi
        elif [[ $InSubMenu == true ]] ; then
            InSubMenu=false
            NextMenuEntryNo=$(( $NextMenuEntryNo + 1 ))
        else
            continue # Future error message?
        fi
        # Set maximum CurrText size to 68 characters.
        CurrText="${CurrText:0:67}"
        AllMenusArr+=($CurrTag "$CurrText")
    fi

    # Example: "menuentry 'Ubuntu' --class ubuntu --class gnu-linux --class gnu" ...
    #          "submenu 'Advanced options for Ubuntu' $menuentry_id_option" ...
    if [[ $line == submenu* ]] ; then
        # line starts with `submenu`
        InSubMenu=true
        ThisSubMenuMajorNo=$NextMenuEntryNo
        NextSubMenuMinorNo=0
        SubMenuList=$SubMenuList$ThisSubMenuMajorNo
        CurrTag=$NextMenuEntryNo
        CurrText="${line#*\'}"
        CurrText="${CurrText%%\'*}"
        AllMenusArr+=($CurrTag "$CurrText") # ie "1 Advanced options for Ubuntu"

    elif [[ $line == menuentry* ]] && [[ $line == *"{"* ]] ; then
        # line starts with `menuentry` and ends with `{`
        if [[ $HideUpstartRecovery == true ]] ; then
            if [[ $line == *"(upstart)"* ]] || [[ $line == *"(recovery mode)"* ]] ; then
                SkippedMenuEntry=true
                continue
            fi
        fi
        InMenuEntry=true
        if [[ $InSubMenu == true ]] ; then
            : # In a submenu, increment minor instead of major which is "sticky" now.
            CurrTag=$ThisSubMenuMajorNo">"$NextSubMenuMinorNo
        else
            CurrTag=$NextMenuEntryNo
        fi
        CurrText="${line#*\'}"
        CurrText="${CurrText%%\'*}"

    else
        continue    # Other stuff - Ignore it.
    fi

done < /boot/grub/grub.cfg

LongVersion=$(grub-install --version)
ShortVersion=$(echo "${LongVersion:20}")
DefaultItem=0

if [[ $HideUpstartRecovery == true ]] ; then
    MenuText="Menu No.     ----------- Menu Name -----------"
else
    MenuText="Menu No. --------------- Menu Name ---------------"
fi

while true ; do

    Choice=$(whiptail \
        --title "Use arrow, page, home & end keys. Tab toggle option" \
        --backtitle "Grub Version: $ShortVersion" \
        --ok-button "Display Grub Boot" \
        --cancel-button "Exit" \
        --default-item "$DefaultItem" \
        --menu "$MenuText" 24 76 16 \
        "${AllMenusArr[@]}" \
        2>&1 >/dev/tty)

    clear
    if [[ $Choice == "" ]]; then break ; fi
    DefaultItem=$Choice

    for (( i=0; i < ${#AllMenusArr[@]}; i=i+2 )) ; do
        if [[ "${AllMenusArr[i]}" == $Choice ]] ; then
            i=$i+1
            MenuEntry="menuentry '"${AllMenusArr[i]}"'"
            break
        fi
    done

    TheGameIsAfoot=false
    while read -r line ; do
        if [[ $line = *"$MenuEntry"* ]]; then TheGameIsAfoot=true ; fi
        if [[ $TheGameIsAfoot == true ]]; then
            echo $line
            if [[ $line = *"}"* ]]; then break ; fi
        fi
    done < /boot/grub/grub.cfg

    read -p "Press <Enter> to continue"

done

exit 0

Именно это раздражало меня больше года, поэтому я сделал быстрый и грязный сценарий для этого. Надеюсь, это поможет другим?

Это объединяет имена в очереди push / pop, но не индексацию меню, так что это могло бы быть лучше, но я зашел так далеко, как только мог.

gawk  'BEGIN {                                                                                                                       
  l=0                                                                                                                                
  menuindex= 0                                                                                                                       
  stack[t=0] = 0                                                                                                                     
}                                                                                                                                    

function push(x) { stack[t++] = x }                                                                                                  

function pop() { if (t > 0) { return stack[--t] } else { return "" }  }                                                              

{                                                                                                                                    

if( $0 ~ /.*menu.*{.*/ )                                                                                                             
{                                                                                                                                    
  push( $0 )                                                                                                                         
  l++;                                                                                                                               

} else if( $0 ~ /.*{.*/ )                                                                                                            
{                                                                                                                                    
  push( $0 )                                                                                                                         

} else if( $0 ~ /.*}.*/ )                                                                                                            
{                                                                                                                                    
  X = pop()                                                                                                                          
  if( X ~ /.*menu.*{.*/ )                                                                                                            
  {                                                                                                                                  
     l--;                                                                                                                            
     match( X, /^[^'\'']*'\''([^'\'']*)'\''.*$/, arr )                                                                               

     if( l == 0 )                                                                                                                    
     {                                                                                                                               
       print menuindex ": " arr[1]                                                                                                   
       menuindex++                                                                                                                   
       submenu=0                                                                                                                     
     } else                                                                                                                          
     {                                                                                                                               
       print "  " (menuindex-1) ">" submenu " " arr[1]                                                                               
       submenu++                                                                                                                     
     }                                                                                                                               
  }                                                                                                                                  
}                                                                                                                                    

}' /boot/grub/grub.cfg

Здесь вы можете увидеть скриншот из моей коробки, показывающий, что он работает

Я только что узнал, что вы можете просто использовать автозаполнение (нажав tab дважды) по командам вроде grub-reboot или же grub-set-default и он даст вам список доступных пунктов меню загрузки. Затем вы можете просто скопировать название, которое вы хотите буквально, вам не нужно использовать номер.

К сожалению, по какой-то причине моя установка Windows 7 так не выглядит.

Другой awk one-liner, который обрабатывает подменю:

 awk -F\' '$1=="menuentry " || $1=="submenu " {print i++ " : " $2}; /\tmenuentry / {print "\t" i-1">"j++ " : " $2};' /boot/grub/grub.cfg

Это может быть ошибочной мыслью, потому что \t используется для идентификации записей подменю.

Это должна быть правильная "строка"...

awk -F\' '/^menuentry / {print $2}' /boot/grub/grub.cfg|cat -n|awk '{print $1-1,$1="",$0}'

Последняя труба удаляет пробелы в начале каждой строки и исправляет последовательность номеров в соответствии с вводом номера grub. Образец вывода:

0   Ubuntu
1   Memory test (memtest86+)
2   Memory test (memtest86+, serial console 115200)
3   Windows 10 (su /dev/sdc1)

Если вы хотите увидеть все записи, а также продвинутые, вы можете использовать

awk -F\' '/(^|| )nuentry / {print $2}' /boot/grub/grub.cfg|cat -n|awk '{print $1-1,$1="",$0}'

но последовательность чисел не подходит для использования с grub-set-default.

В OpenSuSE grub2-Once предоставляет идентификатор меню, который затем можно использовать в других командах. Не так много помощи для пользователей Ubuntu.

# grub2-once --list
     0 openSUSE Leap 42.3
     1 Advanced options for openSUSE Leap 42.3>openSUSE Leap 42.3, with Linux 4.4.172-86-default
     2 Advanced options for openSUSE Leap 42.3>openSUSE Leap 42.3, with Linux 4.4.172-86-default (recovery mode)
     3 Advanced options for openSUSE Leap 42.3>openSUSE Leap 42.3, with Linux 4.4.165-81-default
     4 Advanced options for openSUSE Leap 42.3>openSUSE Leap 42.3, with Linux 4.4.165-81-default (recovery mode)
     5 Advanced options for openSUSE Leap 42.3>openSUSE Leap 42.3, with Linux 4.4.159-73-default
     6 Advanced options for openSUSE Leap 42.3>openSUSE Leap 42.3, with Linux 4.4.159-73-default (recovery mode)
     7 openSUSE 42.1 (x86_64) (on /dev/sda8)
     8 Advanced options for openSUSE 42.1 (x86_64) (on /dev/sda8)>openSUSE Leap 42.1 (on /dev/sda8)
     9 Advanced options for openSUSE 42.1 (x86_64) (on /dev/sda8)>openSUSE Leap 42.1, with Linux 4.1.39-56-default (on /dev/sda8)
    10 Advanced options for openSUSE 42.1 (x86_64) (on /dev/sda8)>openSUSE Leap 42.1, with Linux 4.1.39-53-default (on /dev/sda8)
    11 Advanced options for openSUSE 42.1 (x86_64) (on /dev/sda8)>Install 42.3 (on /dev/sda8)

Решение 1. Использование команды:

входной терминал:

      awk -F\' '/^menuentry/ || /^submenu/ {print "  " $2};/[[:space:]]menuentry[[:space:]]/ {print "       " $2}' /boot/grub/grub.cfg

вывод терминала:

  Убунту
  Расширенные параметры для Ubuntu
       Ubuntu с Linux 6.4.10
       Ubuntu с Linux 6.4.10 (режим восстановления)
       Ubuntu с универсальной версией Linux 6.2.0-26
       Ubuntu с общей версией Linux 6.2.0-26 (режим восстановления)
       Ubuntu с универсальной версией Linux 5.19.0-50
       Ubuntu с Linux 5.19.0-50-generic (режим восстановления)
  Диспетчер загрузки Windows (в /dev/nvme0n1p2)
  Настройки прошивки UEFI



Решение 2. Использованиеawkкоманда со скриптом:

      function show_grub_menu {
    echo ""
    grub-install --version | awk '{print $2,$3}'
    echo ""
    awk -F\' '
        /^menuentry/ || /^submenu/ {print "  " $2};
        /[[:space:]]menuentry[[:space:]]/ {print "       " $2}
    ' /boot/grub/grub.cfg
}


исходный код скрипта и запустите в терминале:
$ show_grub_menu

(GRUB) 2.06-2ubuntu7.2

  Убунту
  Расширенные параметры для Ubuntu
       Ubuntu с Linux 6.4.10
       Ubuntu с Linux 6.4.10 (режим восстановления)
       Ubuntu с универсальной версией Linux 6.2.0-26
       Ubuntu с общей версией Linux 6.2.0-26 (режим восстановления)
       Ubuntu с универсальной версией Linux 5.19.0-50
       Ubuntu с Linux 5.19.0-50-generic (режим восстановления)
  Диспетчер загрузки Windows (в /dev/nvme0n1p2)
  Настройки прошивки UEFI

На EL7:

      grub2-mkconfig 2> /dev/null | grep ^menu 

производит

      menuentry 'CentOS Linux (6.2.9-1.el7.elrepo.x86_64) 7 (Core)' --class centos --class gnu-linux --class gnu --class os --unrestricted $menuentry_id_option 'gnulinux-6.2.9-1.el7.elrepo.x86_64-advanced-c68ae2c5-d205-43f6-9a7e-77ac25a0561f' {
menuentry 'CentOS Linux (5.15.0-105.119.1.el9uek-LXG.x86_64+) 7 (Core)' --class centos --class gnu-linux --class gnu --class os --unrestricted $menuentry_id_option 'gnulinux-5.15.0-105.119.1.el9uek-LXG.x86_64+-advanced-c68ae2c5-d205-43f6-9a7e-77ac25a0561f' {
menuentry 'CentOS Linux (5.15.0-7.86.6.1.el9uek.x86_64-TEST+) 7 (Core)' --class centos --class gnu-linux --class gnu --class os --unrestricted $menuentry_id_option 'gnulinux-5.15.0-7.86.6.1.el9uek.x86_64-TEST+-advanced-c68ae2c5-d205-43f6-9a7e-77ac25a0561f' {
menuentry 'CentOS Linux (5.15.0-7.86.6.1.el9uek.x86_64) 7 (Core)' --class centos --class gnu-linux --class gnu --class os --unrestricted $menuentry_id_option 'gnulinux-5.15.0-7.86.6.1.el9uek.x86_64-advanced-c68ae2c5-d205-43f6-9a7e-77ac25a0561f' {
menuentry 'CentOS Linux (4.19.93) 7 (Core)' --class centos --class gnu-linux --class gnu --class os --unrestricted $menuentry_id_option 'gnulinux-4.19.93-advanced-c68ae2c5-d205-43f6-9a7e-77ac25a0561f' {
menuentry 'CentOS Linux (4.1.42-5.el7.x86_64) 7 (Core)' --class centos --class gnu-linux --class gnu --class os --unrestricted $menuentry_id_option 'gnulinux-4.1.42-5.el7.x86_64-advanced-c68ae2c5-d205-43f6-9a7e-77ac25a0561f' {
menuentry 'CentOS Linux (0-rescue-6eeaf0d9e7104fc8a1077a05e2554ace) 7 (Core)' --class centos --class gnu-linux --class gnu --class os --unrestricted $menuentry_id_option 'gnulinux-0-rescue-6eeaf0d9e7104fc8a1077a05e2554ace-advanced-c68ae2c5-d205-43f6-9a7e-77ac25a0561f' {
Другие вопросы по тегам