0

I'm trying to match only the first block of text between 2 strings: 'menuentry ' and '}' from a file as follows:

Input file:

(some irrelevant text)
menuentry 'My Customized Linux, with Linux 3.10.0-229.14.1.el7.x86_64' --class centos --class gnu-linux --class gnu --class os --unrestricted $menuentry_id_option 'gnulinux-3.10.0-229.14.1.el7.x86_64-advanced-/dev/mapper/sysvg-lv_root' {
        load_video
        set gfxpayload=keep
        insmod gzio
        insmod part_msdos
        insmod xfs
        set root='hd0,msdos1'
        if [ x$feature_platform_search_hint = xy ]; then
          search --no-floppy --fs-uuid --set=root --hint-bios=hd0,msdos1 --hint-efi=hd0,msdos1 --hint-baremetal=ahci0,msdos1 --hint='hd0,msdos1'  2e420275-8578-449d-9217-ce6d9ae35f70
        else
          search --no-floppy --fs-uuid --set=root 2e420275-8578-449d-9217-ce6d9ae35f70
        fi
        linux16 /vmlinuz-3.10.0-229.14.1.el7.x86_64 root=/dev/mapper/sysvg-lv_root ro  nomodeset rd.lvm.lv=sysvg/lv_swap vconsole.keymap=us rd.lvm.lv=sysvg/lv_root vconsole.font=latarcyrheb-sun16 rootfstype=xfs crashkernel=auto quiet LANG=en_US.UTF-8
        initrd16 /initramfs-3.10.0-229.14.1.el7.x86_64.img
}
menuentry 'My Customized Linux (Rescue)' --class centos --class gnu-linux --class gnu --class os --unrestricted $menuentry_id_option 'gnulinux-0-rescue-2e4c8e37e48347b0b4fa7095fbd707db-advanced-/dev/mapper/sysvg-lv_root' {
        load_video
        insmod gzio
        insmod part_msdos
        insmod xfs
        set root='hd0,msdos1'
        if [ x$feature_platform_search_hint = xy ]; then
          search --no-floppy --fs-uuid --set=root --hint-bios=hd0,msdos1 --hint-efi=hd0,msdos1 --hint-baremetal=ahci0,msdos1 --hint='hd0,msdos1'  2e420275-8578-449d-9217-ce6d9ae35f70
        else
          search --no-floppy --fs-uuid --set=root 2e420275-8578-449d-9217-ce6d9ae35f70
        fi
        linux16 /vmlinuz-0-rescue-2e4c8e37e48347b0b4fa7095fbd707db root=/dev/mapper/sysvg-lv_root ro  nomodeset rd.lvm.lv=sysvg/lv_swap vconsole.keymap=us rd.lvm.lv=sysvg/lv_root vconsole.font=latarcyrheb-sun16 rootfstype=xfs crashkernel=auto quiet
        initrd16 /initramfs-0-rescue-2e4c8e37e48347b0b4fa7095fbd707db.img
}
(some more irrelevant text)

output should be:

menuentry 'My Customized Linux, with Linux 3.10.0-229.14.1.el7.x86_64' --class centos --class gnu-linux --class gnu --class os --unrestricted $menuentry_id_option 'gnulinux-3.10.0-229.14.1.el7.x86_64-advanced-/dev/mapper/sysvg-lv_root' {
            load_video
            set gfxpayload=keep
            insmod gzio
            insmod part_msdos
            insmod xfs
            set root='hd0,msdos1'
            if [ x$feature_platform_search_hint = xy ]; then
              search --no-floppy --fs-uuid --set=root --hint-bios=hd0,msdos1 --hint-efi=hd0,msdos1 --hint-baremetal=ahci0,msdos1 --hint='hd0,msdos1'  2e420275-8578-449d-9217-ce6d9ae35f70
            else
              search --no-floppy --fs-uuid --set=root 2e420275-8578-449d-9217-ce6d9ae35f70
            fi
            linux16 /vmlinuz-3.10.0-229.14.1.el7.x86_64 root=/dev/mapper/sysvg-lv_root ro  nomodeset rd.lvm.lv=sysvg/lv_swap vconsole.keymap=us rd.lvm.lv=sysvg/lv_root vconsole.font=latarcyrheb-sun16 rootfstype=xfs crashkernel=auto quiet LANG=en_US.UTF-8
            initrd16 /initramfs-3.10.0-229.14.1.el7.x86_64.img

}

I'm using sed for this as follows:

sed -n '/^menuentry /,/^}$/p;' /boot/grub2/grub.cfg

But always get the whole text between the first 'menuentry' and last '}'

    [root@ball ~]# sed -n '/^menuentry /,/^}$/p;' /boot/grub2/grub.cfg
menuentry 'My Customized Linux, with Linux 3.10.0-229.14.1.el7.x86_64' --class centos --class gnu-linux --class gnu --class os --unrestricted $menuentry_id_option 'gnulinux-3.10.0-229.14.1.el7.x86_64-advanced-/dev/mapper/sysvg-lv_root' {
        load_video
        set gfxpayload=keep
        insmod gzio
        insmod part_msdos
        insmod xfs
        set root='hd0,msdos1'
        if [ x$feature_platform_search_hint = xy ]; then
          search --no-floppy --fs-uuid --set=root --hint-bios=hd0,msdos1 --hint-efi=hd0,msdos1 --hint-baremetal=ahci0,msdos1 --hint='hd0,msdos1'  2e420275-8578-449d-9217-ce6d9ae35f70
        else
          search --no-floppy --fs-uuid --set=root 2e420275-8578-449d-9217-ce6d9ae35f70
        fi
        linux16 /vmlinuz-3.10.0-229.14.1.el7.x86_64 root=/dev/mapper/sysvg-lv_root ro  nomodeset rd.lvm.lv=sysvg/lv_swap vconsole.keymap=us rd.lvm.lv=sysvg/lv_root vconsole.font=latarcyrheb-sun16 rootfstype=xfs crashkernel=auto quiet LANG=en_US.UTF-8
        initrd16 /initramfs-3.10.0-229.14.1.el7.x86_64.img
}
menuentry 'My Customized Linux (Rescue)' --class centos --class gnu-linux --class gnu --class os --unrestricted $menuentry_id_option 'gnulinux-0-rescue-2e4c8e37e48347b0b4fa7095fbd707db-advanced-/dev/mapper/sysvg-lv_root' {
        load_video
        insmod gzio
        insmod part_msdos
        insmod xfs
        set root='hd0,msdos1'
        if [ x$feature_platform_search_hint = xy ]; then
          search --no-floppy --fs-uuid --set=root --hint-bios=hd0,msdos1 --hint-efi=hd0,msdos1 --hint-baremetal=ahci0,msdos1 --hint='hd0,msdos1'  2e420275-8578-449d-9217-ce6d9ae35f70
        else
          search --no-floppy --fs-uuid --set=root 2e420275-8578-449d-9217-ce6d9ae35f70
        fi
        linux16 /vmlinuz-0-rescue-2e4c8e37e48347b0b4fa7095fbd707db root=/dev/mapper/sysvg-lv_root ro  nomodeset rd.lvm.lv=sysvg/lv_swap vconsole.keymap=us rd.lvm.lv=sysvg/lv_root vconsole.font=latarcyrheb-sun16 rootfstype=xfs crashkernel=auto quiet
        initrd16 /initramfs-0-rescue-2e4c8e37e48347b0b4fa7095fbd707db.img
}

Any ideas?

adiflinux
  • 33
  • 5

3 Answers3

2

one line sed

sed -n '/^menuentry/,/\}$/{p;/^\}$/q}'

/^\}$/q means that "if the line matches with pattern /^\}$/ then quit"

ymonad
  • 136
  • 1
1

This works for me using multiple passes

sed -n '/^menuentry /,$p' /boot/grub2/grub.cfg | tr '\n' '~' | sed 's/~menuentry.*//' | tr '~' '\n'

Explanation

  • sed -n '/^menuentry /,$p' /boot/grub2/grub.cfg - remove the head of the file up to the first menuentry
  • tr '\n' '~' - convert the output into a single line
  • sed 's/~menuentry.*//' - use sed to remove from \nmenuentry (which is now ~menuentry) to the end of the string
  • tr '~' '\n' - restore the string back to mulitiline output
the_velour_fog
  • 497
  • 2
  • 4
  • 14
1

If Perl will do...

    perl -lne '$p=1 if(/^menuentry/);print if $p;exit if (/^}$/)' /boot/grub2/grub.cfg

gives

menuentry 'My Customized Linux, with Linux 3.10.0-229.14.1.el7.x86_64' --class centos --class gnu-linux --class gnu --class os --unrestricted $menuentry_id_option 'gnulinux-3.10.0-229.14.1.el7.x86_64-advanced-/dev/mapper/sysvg-lv_root' {
        load_video
        set gfxpayload=keep
        insmod gzio
        insmod part_msdos
        insmod xfs
        set root='hd0,msdos1'
        if [ x$feature_platform_search_hint = xy ]; then
          search --no-floppy --fs-uuid --set=root --hint-bios=hd0,msdos1 --hint-efi=hd0,msdos1 --hint-baremetal=ahci0,msdos1 --hint='hd0,msdos1'  2e420275-8578-449d-9217-ce6d9ae35f70
        else
          search --no-floppy --fs-uuid --set=root 2e420275-8578-449d-9217-ce6d9ae35f70
        fi
        linux16 /vmlinuz-3.10.0-229.14.1.el7.x86_64 root=/dev/mapper/sysvg-lv_root ro  nomodeset rd.lvm.lv=sysvg/lv_swap vconsole.keymap=us rd.lvm.lv=sysvg/lv_root vconsole.font=latarcyrheb-sun16 rootfstype=xfs crashkernel=auto quiet LANG=en_US.UTF-8
        initrd16 /initramfs-3.10.0-229.14.1.el7.x86_64.img
}

or this:

perl -lne 'BEGIN{$/="\nmenuentry "};if($.==2){print $/,$_;last}' /boot/grub2/grub.cfg

(This version sets the perl line splitting to end with the start of the menuentry line, then prints the "second" stanza which is actually the one you want.