Convert menu.lst to grub.cfg with grub-menulst2cfg
grub-menulst2cfg translates an ancient menu.lst into GRUB 2 configuration text without touching the live boot partition. You will turn the legacy file into GRUB 2 configuration text, save it separately, and inspect the translated entries before anything gets near /boot.
The route
Jump straight to the step you need, or tick off Done means at the end.
Allow about 15 minutes for a small file, plus whatever time it takes to test the result on the machine that will actually use it.
This guide uses grub-menulst2cfg from the installed grub-common package, version 2.12-1ubuntu7.3. The local manual page, dated March 2025, documents the syntax as grub-menulst2cfg [INFILE [OUTFILE]] and nothing more: no option list, no conversion reference. Everything below is behaviour verified against this installed command.
1. Check the tool and preserve the source
Run this as your ordinary user. Conversion reads the legacy file and writes generated text; it needs no root as long as both files sit in a directory you can already access.
$ command -v grub-menulst2cfg
/usr/bin/grub-menulst2cfg
$ dpkg-query -W grub-common
grub-common 2.12-1ubuntu7.3
Make a working copy of the input before you experiment, and keep the original somewhere safe. The converter is a migration aid, not an editor with an undo command:
$ cp --preserve=all /path/to/menu.lst /path/to/menu.lst.before-conversion
$ test -r /path/to/menu.lst && echo 'input is readable'
input is readable
Checkpoint
You should have a readable source file and a separate backup. Do not edit /boot/grub/grub.cfg in place as your first move.
2. Review the legacy input
Look for the directives that become menu entries and boot commands: a default entry, a timeout, one or more title blocks, a root device, a kernel line, and an optional initrd line. A small legacy file might look like this:
default 0
timeout 5
title Ubuntu 24.04
root (hd0,0)
kernel /vmlinuz root=/dev/sda1 ro quiet
initrd /initrd.img
title Recovery
root (hd0,0)
kernel /vmlinuz root=/dev/sda1 single
That is illustrative, not something to paste into a real system without swapping in your own kernel paths, root device and entry titles. Check the actual file instead:
$ sed -n '1,240p' /path/to/menu.lst
Tip
Watch the disk numbering closely. Legacy GRUB and GRUB 2 do not always present the same disk and partition number the same way. On the test file above, the installed converter turned (hd0,0) into (hd0,1) in its output. Treat that as a value to verify, never as a reason to edit the source blindly.
3. Generate a review copy
Pass the input as the first argument and a new output path as the second. The output is created or replaced outright, so pick a staging name that is not your live configuration:
$ grub-menulst2cfg /path/to/menu.lst /tmp/grub.cfg.converted
$ printf 'converter status: %s\n' "$?"
converter status: 0
$ sed -n '1,240p' /tmp/grub.cfg.converted
For the sample input, the result looks like this:
set default='0'; if [ x"$default" = xsaved ]; then load_env; set default="$saved_entry"; fi
set timeout=5
menuentry 'Ubuntu 24.04' {
set root='(hd0,1)'; set legacy_hdbias='0'
legacy_kernel '/vmlinuz' '/vmlinuz' 'root=/dev/sda1' 'ro' 'quiet'
legacy_initrd '/initrd.img' '/initrd.img'
}
menuentry 'Recovery' {
set root='(hd0,1)'; set legacy_hdbias='0'
legacy_kernel '/vmlinuz' '/vmlinuz' 'root=/dev/sda1' 'single'
}
Give only the input path and the converter writes to standard output instead, handy for a quick look or a pipeline:
$ grub-menulst2cfg /path/to/menu.lst | sed -n '1,120p'
With an explicit output path it prints no progress message and just returns status 0 on success. That generated text is not a report, it is GRUB commands, including compatibility helpers like legacy_kernel. Read it with the GRUB installation that will load it in mind.
4. Check the translated entries before installing anything
Compare every value that matters against the legacy file. Menu titles should be recognisable, the default index should point at the intended entry, the timeout should be deliberate, and each kernel argument should have survived as a separate argument, with an initrd line producing a matching legacy_initrd command:
$ grep -nE '^(set default|set timeout|menuentry| set root| legacy_)' /tmp/grub.cfg.converted
1:set default='0'; if [ x"$default" = xsaved ]; then load_env; set default="$saved_entry"; fi
2:set timeout=5
3:menuentry 'Ubuntu 24.04' {
4: set root='(hd0,1)'; set legacy_hdbias='0'
5: legacy_kernel '/vmlinuz' '/vmlinuz' 'root=/dev/sda1' 'ro' 'quiet'
6: legacy_initrd '/initrd.img' '/initrd.img'
9:menuentry 'Recovery' {
10: set root='(hd0,1)'; set legacy_hdbias='0'
11: legacy_kernel '/vmlinuz' '/vmlinuz' 'root=/dev/sda1' 'single'
This text check catches missing entries, but it cannot prove the named disk actually holds that kernel, or that the machine will boot. If the output has the wrong root device or kernel path, fix the source or the migration plan; do not compensate by guessing at GRUB numbering.
5. Decide how to deploy it
Warning
Do not copy the review file over a working /boot/grub/grub.cfg just because conversion returned status 0. Success there only means the program parsed and wrote the input; it validates nothing about your disks, kernels, modules, firmware mode or overall GRUB setup.
If your system has a documented migration procedure, follow it and take a dated backup first. Reading the live file is unprivileged, but the backup write needs elevated access because /boot/grub is normally protected:
$ sudo cp --preserve=all /boot/grub/grub.cfg /boot/grub/grub.cfg.before-menu-lst-migration
$ sudo test -r /boot/grub/grub.cfg && echo 'live configuration is readable'
live configuration is readable
The converter itself never needs elevated privileges; installation might, but the exact destination and surrounding GRUB fragments are distribution-specific and outside this sparse manual page. A boot configuration change can leave the machine unbootable, so line up console or rescue access before you make one.
Recovery
Boot into your recovery path or a working system, then restore the backup only after checking the destination:
$ sudo test -f /boot/grub/grub.cfg.before-menu-lst-migration
$ sudo cp --preserve=all /boot/grub/grub.cfg.before-menu-lst-migration /boot/grub/grub.cfg
Do not delete that backup until you have successfully booted and confirmed the menu. Deleting the recovery copy is irreversible.
6. Diagnose failures without touching boot state
A missing or unreadable input gives a non-zero exit status and an error on standard error. Check the path and permissions first:
$ grub-menulst2cfg /path/to/missing-menu.lst /tmp/grub.cfg.converted
cannot open \`/path/to/missing-menu.lst': No such file or directory
$ printf 'converter status: %s\n' "$?"
converter status: 1
$ ls -l /path/to/menu.lst
$ test -r /path/to/menu.lst && echo readable
The command takes at most two positional paths. Its installed help is only Usage: grub-menulst2cfg [INFILE [OUTFILE]], so do not invent long options for selecting a root device, changing numbering or validating a configuration. Those decisions belong in your reviewed input and your deployment process.
Done means
- Tool and input checked. The installed
grub-commonversion and the source file were confirmed. - Original preserved. The
menu.lsthas a separate backup copy. - Conversion verified. A converted file was written to a staging path and returned status 0.
- Entries reviewed. Titles, default, timeout, root device, kernel arguments and initrd commands were checked.
- Numbering verified. The translated disk numbering was checked against the actual machine.
- No blind overwrite. The live boot configuration was only replaced with a backup and a recovery path in hand.