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 Answer 1

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

You must log in to answer this question.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.