For a command such as
grubby --info=ALL
the output received is something of the sort –
index=3
kernel="/boot/vmlinuz-4.18.0-80.el8.x86_64"
args="ro crashkernel=auto resume=/dev/mapper/cl-swap rd.lvm.lv=cl/root rd.lvm.lv=cl/swap rhgb quiet"
root="/dev/mapper/cl-root"
initrd="/boot/initramfs-4.18.0-80.el8.x86_64.img"
title="CentOS Linux (4.18.0-80.el8.x86_64) 8 (Core)"
id="d7fe995b9d09403896e1e56a2b02a947-4.18.0-80.el8.x86_64"
index=4
kernel="/boot/vmlinuz-0-rescue-d7fe995b9d09403896e1e56a2b02a947"
args="ro crashkernel=auto resume=/dev/mapper/cl-swap rd.lvm.lv=cl/root rd.lvm.lv=cl/swap rhgb quiet"
root="/dev/mapper/cl-root"
initrd="/boot/initramfs-0-rescue-d7fe995b9d09403896e1e56a2b02a947.img"
title="CentOS Linux (0-rescue-d7fe995b9d09403896e1e56a2b02a947) 8 (Core)"
id="d7fe995b9d09403896e1e56a2b02a947-0-rescue"
I can pipe this output into an array, to try and refer to each block individually –
mapfile -t my_array < <(grubby --info=ALL )
However, this saves each element as a separate string in my_array
, such as
printf '%sn' "${my_array[0]}"
Output –
index=3
Perhaps I can access these elements for comparison based on regularity of offset (7 in this case for each subitem in subsequent blocks).
However, I’d like to retrieve the string value of these array components, doing a
printf '%sn' "${my_array[1]}"
gives me
kernel="/boot/vmlinuz-4.18.0-80.el8.x86_64"
from which I’d like to get the value…
Also, if someone could suggest a better way, such as by accessing the value individually in each file, maybe something like –
cd /boot/loader/entries
for filename in $(find -type f -name '*.conf'); do
//Access this field
Not sure how to do it, though..
2
Answers
Subject to the comments about your output of
grubby
containing multipleindex=
lines where thename=value
pairs have the same names under each index, the general way you handle parsing values from string variables in bash is with a parameter expansion (with substring removal). I say "general" way because the following parameter expansions are also provided in POSIX shell so your script will be portable to other shells. (bash provides an additional number of expansions that are bash-only)A summary of the parameter expansions with substring removal are:
(note: pattern can contain the normal globbing characters such as
'*'
, andfront
above is the same as"from the left" andback
is "from the right" which you will see used interchangeably)For your output above, you can loop over the lines separating the
name=value
pairs intoname
andvalue
. Since the names repeat under each index, you can’t use an associative arrayarray[name]="value"
directly or you will only end up with the last values. (you can save theindex=X
and usearray[X name]="value"
, but that gets messy when you want to retrieve things)You have another caveat with the
args
name that contains'='
within thevalue
portion. (which you would want to use the${var#pattern}
form to isolatename=value
based on the first'='
from the front (left))As an example, you could redirect the output of
grubby
directly as you have done using a process substitution (bash-only) or redirect it to a file and read line from the file with something similar to:Example Use/Output
Reading your
grubby
data from a file would result in:So that is one way to approach the separation. The other would be to use
awk
which allows the same approach to simulating 2D arrays using a','
to separate multiple index values (seeSUBSEP
inman awk
). However, if you can get what you need without storing all values — then you eliminate the simulated 2D array issue altogether.Look things over and let me know if you have further questions.
In bash, it is possible to create an associative array, say named
grubby
, and access its elements like${grubby[index,key]}
. For instance${grubby[3,kernel]}
should expand to/boot/vmlinuz-4.18.0-80.el8.x86_64
.Example script:
The output of the
grubby
command should be redirected to the script: