CarstenP
CarstenP

Reputation: 241

Tricky handling of associative array'ish data

I have a configuration file which looks like this:

#!/bin/bash

# lots of other stuff

declare -A PARTITIONS

PARTITIONS[ROOT,DEV]=/dev/mmcblk0p2
PARTITIONS[ROOT,MNT]=/
PARTITIONS[ROOT,FSTYPE]=ext4
PARTITIONS[ROOT,OPTS]='rw,suid,exec,auto,nouser,async,errors=remount-ro,noatime,nodiratime,commit=120 0 1'
PARTITIONS[ROOT,START]=64MB
PARTITIONS[ROOT,END]=6143.9MB
PARTITIONS[ROOT,OWNER]=root.root
PARTITIONS[ROOT,PERMS]=755

PARTITIONS[DATA,DEV]=/dev/mmcblk0p7
PARTITIONS[DATA,MNT]=/data
PARTITIONS[DATA,FSTYPE]=xfs
PARTITIONS[DATA,OPTS]='rw,noexec,auto,user,suid,noatime,nodiratime,async,logbufs=4,noquota 0 3'
PARTITIONS[DATA,START]=12288MB
PARTITIONS[DATA,END]=-1s
PARTITIONS[DATA,OWNER]=root.root
PARTITIONS[DATA,PERMS]=755

etc etc etc.

When I include it in the configuring script and iterate the keys of the AA, I get them in no particular order. The right parts of the keys (DEV, MNT...) are fixed, but not all are mandatory, while the left parts can be kind of random (just a mnemonic).

What I need is a list of the left parts to know which partitions must be created, then find out which of the right parts are defined (and if not, set a default value), so each partition will be well-defined before actually creating the partition, adding it to fstab, mounting...

We are talking about fresh systems here. The only two options to accomplish the task are Bash and/or Perl. No JavaScript, no Python, no C# Script, sorry. Sed and Awk are available. Because the setup steps before are done in Bash, I'd prefer a plain Bash (plus Sed/Awk, if needed) solution.

Of course its possible to change the configuration file. The only mandatory thing is to keep the flexibility of the left part of the keys.

Upvotes: 0

Views: 61

Answers (2)

rici
rici

Reputation: 241881

While I tend to agree with @EdMorton's comment that awk is a superior tool, this problem is not particularly complicated, and bash is probably just fine:

# Find all the left-hand keys
declare -A keys
for key in "${!PARTITIONS[@]}"; do
  keys[${key%%,*}]=1
done

# Set defaults and/or check validity
errors=0
for key in "${!keys[@]}"; do
  # Set a default
  : "${PARTITIONS[$key,FSTYPE]:=ext4}"

  # Make sure a setting exists.
  # -v requires v4.2; otherwise use -n/-z. Maybe you
  # want those anyway, since a blank config might be an error.
  if [[ ! -v PARTITIONS[$key,MNT] ]]; then
    printf "MNT key missing for partition %s\n" "$key" >>/dev/stderr
    # Remove it from the set so it doesn't show up later
    unset keys[$key]
    ((errors++))
  fi

  # Etc.
done

# For debugging purposes, just print out the settings
for key in "${!keys[@]}"; do
  printf "$key:"
  for field in DEV MNT FSTYPE OPTS START END OWNER PERMS; do
    printf " %s=%b" $field "${PARTITIONS[$key,$field]}"
  done
  echo
done 

if ((errors)); then
  printf "Config errors. Not proceeding\n" >> /dev/stderr
  return 1
fi

# Do what needs to be done
# probably another loop over keys

Upvotes: 1

karakfa
karakfa

Reputation: 67507

awk to the rescue!

$ awk -F'[\\]\\[,]' '/^PARTITIONS/{a[$2]=a[$2]?a[$2] OFS $3:$3}
                               END{for(k in a) print k ": " a[k]}' conf

DATA: DEV MNT FSTYPE OPTS START END OWNER PERMS
ROOT: DEV MNT FSTYPE OPTS START END OWNER PERMS

you can change the separator between the right components by setting up OFS.

Upvotes: 1

Related Questions