0

I'm trying to create an array that looks like this:

0       kernel
1       /boot/vmlinuz-4.8.0-1.el7.elrepo.x86_64 
2       kernel
3       /boot/vmlinuz-4.7.3-1.el7.elrepo.x86_64

Using the grubby command of which the ouput for the entires I'm looking for are:

index=2
kernel=/boot/vmlinuz-4.8.0-1.el7.elrepo.x86_64
root=/dev/mapper/<my_vol>-root
initrd=/boot/initramfs-4.8.0-1.el7.elrepo.x86_64.img
title=CentOS Linux (4.8.0-1.el7.elrepo.x86_64) 7 (Core)
index=3
kernel=/boot/vmlinuz-4.7.3-1.el7.elrepo.x86_64
root=/dev/mapper/<my_vol>-root
initrd=/boot/initramfs-4.7.3-1.el7.elrepo.x86_64.img
title=CentOS Linux (4.7.3-1.el7.elrepo.x86_64) 7 (Core)

(I've removed the "args=" line for sanitisation purposes)

When I try to use the following command which works... (err... for the first 2 elements of the array). It decided that 2 indicies should be squashed into one.

IFS='=' read -a KERNELS <<< $(sudo grubby --info=ALL |grep -v rescue |grep -E 4.[78] |grep kernel)

0       kernel
1       /boot/vmlinuz-4.8.0-1.el7.elrepo.x86_64 kernel
2       /boot/vmlinuz-4.7.3-1.el7.elrepo.x86_64

First of why is it doing this? And how can I fix it?

I understand that there are other ways I could solve this problem but I want to understand what's going on here:

for i in ${KERNELS[@]}; do echo $i; done
kernel
/boot/vmlinuz-4.8.0-1.el7.elrepo.x86_64
kernel
/boot/vmlinuz-4.7.3-1.el7.elrepo.x86_64

for i in ${!KERNELS[@]}; do echo $i ${KERNELS[$i]}; done
0 kernel
1 /boot/vmlinuz-4.8.0-1.el7.elrepo.x86_64 kernel
2 /boot/vmlinuz-4.7.3-1.el7.elrepo.x86_64

I suspect it has something to do with the fact that when you run

sudo grubby --info=ALL |grep -v rescue |grep -E 4.[78] |grep kernel
kernel=/boot/vmlinuz-4.8.0-1.el7.elrepo.x86_64
kernel=/boot/vmlinuz-4.7.3-1.el7.elrepo.x86_64

You get two lines of output and the IFS= is separating on '=' and ignoring the '\n'

I've tried using awk '{print}' ORS=' ' ideas to output everything on one line but it gets messy.

There has to be a more elegant way to use the hereto string with multiple lines of output. Surely...

3
  • yup I sure can. Commented Mar 7, 2017 at 11:26
  • As an aside, the long grep pipeline seems to beg for an Awk solution. grubby --info=ALL | awk 'BEGIN { ORS="=" } !/rescue/ && /4\.[78]/ && /kernel/' -- notice also the requirement to backslash a literal period, and see also useless use of grep Commented Mar 7, 2017 at 12:37
  • Quote your parameter expansions: for i in ${!KERNELS[@]}; do echo "$i" "${KERNELS[i]}"; done. You'll see that ${KERNELS[1]} contains the newline that separates the two lines in the output of the pipeline. A here-string isn't appropriate here. (Also, what version of bash are you using? A bug dealing with pre-command environment settings and here-strings that wasn't completely fixed until bash 4.4 may be affecting your results.) Commented Mar 7, 2017 at 12:57

2 Answers 2

1

You can use process substitution combined with read directive:

arr=()

while IFS='=' read -r k v; do
   [[ $k = "kernel" ]] && { arr+=("$k"); arr+=("$v"); }
done < <(sudo grubby --info=ALL)

Check array content:

printf '[%s]\n' "${arr[@]}"

[kernel]
[/boot/vmlinuz-4.8.0-1.el7.elrepo.x86_64]
[kernel]
[/boot/vmlinuz-4.7.3-1.el7.elrepo.x86_64]
Sign up to request clarification or add additional context in comments.

Comments

0

Ok so I accidently just has a moment of clarity using the exta info posted above

IFS='=' read -a KERNELS <<< $(sudo grubby --info=ALL |grep -v rescue |grep -E 4.[78] |grep kernel | awk '{print}' ORS='=')

for i in ${!KERNELS[@]}; do echo ${KERNELS[$i]} $i; done
kernel 0
/boot/vmlinuz-4.8.0-1.el7.elrepo.x86_64 1
kernel 2
/boot/vmlinuz-4.7.3-1.el7.elrepo.x86_64 3

I've used awk to get around the fact that there are multiple lines with terminating '\n' and instead inserted a '=' which will be the delimiting factor in building the array. =]

3 Comments

You don't really need to use 2 grep commands and one awk after grubby command to parse it out. Just a single awk can handle it all.
I know this. But since unix pipes, unix programs, and the unix paradigm in general is based on small, simple pieces chained together, why would I replace 3 simple easily readable/editable stages for ascii vomit I'm going to have to groan at in 6 months. Also I have other problems to solve ^_^ but thanks for your input!
It's your choice but in case your input is big than invoking 3 external calls will hurt you big time while processing.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.