Search code examples
arraysbashfor-loopeof

How to print a variable from an associative array and a multiline string from a loop cycle into a heredoc


I need to return variables (from 1 to 4) and the selected values from the associative array into the heredoc.

Variables

BASE=ppp-multi-image
DEV=sdb # i.e. sdb or mmcblk0
ATTR=RequiredPartition,LegacyBIOSBootable
SIZE=11GiB

Associative array

declare -A NameUrl
NameUrl[uboot]=https://uboot.ext
NameUrl[arch]=https:/archlinux.ext
NameUrl[manjaro]=https://manjaro.ext
NameUrl[mobian]=https://mobian.ext
NameUrl[extra]=https://extra.ext
$ sudo sfdisk /dev/$DEV --wipe always <<EOF
label: gpt
first-lba: 64
table-length: 10
attrs=RequiredPartition, type=D7B1F817-AA75-2F4F-830D-84818A145370, start=64, size=32704 name="$BASE-<# how do I return "uboot" here as first variable? #>"

for NameUrl in "${!NameUrl[@]}"; do
echo "attrs=\"$ATTR\", size=$SIZE, name=\"$BASE-${NameUrl}\""
done | sort
<# this loop is not returned into EOF string #>

attrs="$ATTR", size=+, name="extra"
EOF

Final result should be like following

$ sfdisk /dev/sdb --wipe always <<EOF
label: gpt
first-lba: 64
table-length: 10
attrs=RequiredPartition, type=D7B1F817-AA75-2F4F-830D-84818A145370, start=64, size=32704 name="ppp-multi-image-uboot"
attrs="RequiredPartition,LegacyBIOSBootable", size=11GiB, name="ppp-multi-image-arch"
attrs="RequiredPartition,LegacyBIOSBootable", size=11GiB, name="ppp-multi-image-manjaro"
attrs="RequiredPartition,LegacyBIOSBootable", size=11GiB, name="ppp-multi-image-mobian"
attrs="RequiredPartition,LegacyBIOSBootable", size=+, name="extra"
EOF

Solution

  • You cannot embed shell code directly into a heredoc. How is the shell supposed to recognize that it's meant as code, not data? The whole idea has bad code smell, but if for some reason you think that's your best alternative (as opposed, say, to piping the appropriate data into the command's standard input) then you can take advantage of the fact that command substitution is performed inside heredocs, provided that the delimiter word is presented unquoted.

    Additionally, you seem to want to pull out not just "uboot" but also "extra" as special cases. You can do that within your for loop by simply testing for those keys and producing no output for them, leaving them to be handled separately. However, I would consider instead just omitting them from the NameUrl array, or else creating a separate array that omits them.

    For example:

    $ sudo sfdisk "/dev/$DEV" --wipe always <<EOF
    label: gpt
    first-lba: 64
    table-length: 10
    attrs="RequiredPartition, type=D7B1F817-AA75-2F4F-830D-84818A145370, start=64", size=32704 name="${BASE}-uboot"
    $(
    for name in "${!NameUrl[@]}"; do
      case ${name} in uboot|extra) continue ;; esac
      printf '%s\n' "attrs=\"$ATTR\", size=$SIZE, name=\"$BASE-${name}\""
    done | sort
    )
    attrs="$ATTR", size=+, name="extra"
    EOF
    

    Note that I took the liberty of adding double quotes around the attributes for the uboot line, for consistency with the other lines.