简体   繁体   中英

Bash array grouping elements

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...

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]

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. =]

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM