0

I have these bash functions for loading an INI file and parsing it into two arrays one for keys and the second for values then use these arrays to write a new INI file

declare -a ini_keys
declare -a ini_values

load_settings() { echo "Loading settings from "$1"" ini_keys=() ini_values=() if [ -f "$1" ]; then ini_keys=($(awk -F ' = ' '/^[a-z]/ {print $1}' "$1")) ini_values=($(awk -F ' = ' '/^[a-z]/ {print $2}' "$1")) return 0 fi echo "Missing "$1"" return 1 }

save_settings() { echo "Saving settings to "$1"" [ -f "$1" ] && mv "$1" "$1.bak" for index in "${!ini_keys[@]}"; do echo "${ini_keys[$index]}=${ini_values[$index]}" >> "$1" done }

load_settings config.ini save_settings new-config.ini

The problem I'm having is that sometimes I got some empty values

config.ini

key_01=value_01
key_02=value_02
key_03=
key_04=value_04
key_05=value_05

So I end up with a "new-config.ini" like

key_01=value_01
key_02=value_02
key_03=value_04
key_04=value_05
key_05=

How can I fix this to preserve the empty values in array and in new written INI file?

1 Answers1

1
ini_values=($(awk -F ' *= *' '/^[a-z]/ {print $2}' "$1"))

You're relying on word splitting here, which indeed does remove empty fields, but will also lead into problems if any of your values have whitespace; they'll get split into multiple fields. And glob characters may expand to filenames. Discussed somewhat here: Why does my shell script choke on whitespace or other special characters?

Also, running an awk instance or two for every input line is rather a high overhead.

Luckily, the shell's read builtin can split input on the =, so you can do something like below. Here, with associative arrays, since they can represent key-value relations directly. But you could use regular arrays if you really want.

#!/bin/bash

configfile=config.ini declare -A config

read the ini file in

while IFS== read -r key val; do config+=(["$key"]="$val") done < "$configfile"

print and change one value

k=key_05 echo "key $k -> value ${config[$k]}" config[$k]="foo bar"

print it all out

for key in "${!config[@]}"; do printf "%s=%s\n" "$key" "${config[$key]}" done

ilkkachu
  • 138,973